『最短路·拓扑排序』益智游戏

本文介绍了益智游戏的解决方案,通过证明公共部分必须为连续一段,预处理A到B和C到D的最短路图,并利用Dijkstra算法,构建DAG图进行拓扑排序,找到最短路图的最长链作为最优解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

在这里插入图片描述

题解

  • 首先证明一个结论:公共部分一定是连续的一段
    因为如果公共部分分成了两段,可以将中间部分强行拼成一段。即一个人可以走另一个人在断开部分的路线,这样一定可以时答案变优。因此,公共部分一定是连续的一段。

  • step2:我们可以预处理A到B的最短路图和C到D的最短路图。
    具体的实现方法时建立正图和反图分别以这四个点跑Dijkstra,枚举每一条边(x,y,v)看看是否满足:dis1x+dis2y+v=dis1B/Ddis1_x+dis2_y+v=dis1_{B/D}dis1x+dis2y+v=dis1B/D

  • step3:我们发现这张最短路图就是一张DAG,因此我们只需要进行一遍拓扑排序求出最短路图的最长链即可=为最终的答案。

#include <bits/stdc++.h>

using namespace std;
const int N = 100000;

vector < pair<int,int> > G1[N], G2[N];

int n, m, A, B, C, D, tot = 0;
int vis[5][N], dis[5][N], Link[N], rd[N], used[N], f[N];

struct node {
	int y, next;
} e[N*2];

void Dijkstra(int num,vector< pair<int,int> >a[N],int st)
{
	memset(vis[num],0,sizeof vis[num]);
	memset(dis[num],30,sizeof dis[num]);
	dis[num][st] = 0;
	priority_queue< pair<int,int> > q;
	q.push(make_pair(0,st));
	while (q.size())
	{
		int x = q.top().second; q.pop();
		if (vis[num][x]) continue; vis[num][x] = 1;
		for (int i=0;i<a[x].size();++i)
		{
			int y = a[x][i].first;
			int v = a[x][i].second;
			if (dis[num][x] + v < dis[num][y]) {
				dis[num][y] = dis[num][x] + v;
				q.push(make_pair(-dis[num][y],y));
			}
		}
	}
	return;
}

void add(int x,int y)
{
	e[++tot] = node{y,Link[x]};
	Link[x] = tot, rd[y] ++;
}

int Topsort(void)
{
	queue <int> q;
	for (int i=1;i<=n;++i)
	    if (rd[i] == 0) q.push(i);
	while (q.size())
	{
		int x = q.front(); q.pop();
		for (int i=Link[x];i;i=e[i].next)
		{
			int y = e[i].y;
			rd[y] --;
			f[y] = max(f[x]+1,f[y]);
			if (!rd[y]) q.push(y);
		}
	}
	int ans = 0;
	for (int i=1;i<=n;++i)
	    ans = max(ans,f[i]);
	return ans;
}

int main(void)
{
	freopen("game.in","r",stdin);
	freopen("game.out","w",stdout);
	scanf("%d %d", &n, &m);
	for (int i=1;i<=m;++i)
	{
		int x, y, v;
		scanf("%d %d %d", &x, &y, &v);
		G1[x].push_back(make_pair(y,v));
		G2[y].push_back(make_pair(x,v));
	} 
	scanf("%d %d %d %d", &A, &B, &C, &D);
	Dijkstra(1,G1,A);
	Dijkstra(2,G1,C);
	Dijkstra(3,G2,B);
	Dijkstra(4,G2,D);
	if (dis[1][B] == dis[1][0] || dis[2][D] == dis[2][0])
		return puts("-1"), 0;
	for (int x=1;x<=n;++x)
	    for (int i=0;i<G1[x].size();++i)
	    {
	    	int y = G1[x][i].first;
	    	int v = G1[x][i].second;
	    	if (dis[1][x]+v+dis[3][y] == dis[1][B]
			 && dis[2][x]+v+dis[4][y] == dis[2][D]) add(x,y);
	    }
	cout<<1+Topsort()<<endl;
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值