SDOI2009Elaxia的路线--想法+dijkstra

本文介绍了一种算法,用于解决在一个无向图中找到两条特定路径的最短路问题,同时确保这两条路径间的最大公共路径尽可能长。通过预处理最短路径并进行拓扑排序来实现。

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

题意:给出一个无向图和s1,t1,s2,t2,求出s1-t1和s2-t2的最短路,使得这两条路径的最大公共路径最长。

做法:因为两点间最短路可能不唯一,所以不能直接构造。

如果一条边u-v在s-t的最短路径中,那么d[s][u]+c[u][v]+d[v][t]=d[s][t]。

所以预处理以s1,t1,s2,t2为原点的最短路径,再找出对s1,t1和s2,t2都满足上面式子的边,然后删去其他边,再跑一遍拓扑排序就可以了。

#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int maxn=1505,inf=0x3f3f3f3f;
int Begin[maxn],to[maxn*maxn*2],Next[maxn*maxn*2],c[maxn*maxn*2],e,n;
bool is_ok[maxn*maxn*2];
void add(int u,int v,int w){
	to[++e]=v,Next[e]=Begin[u],Begin[u]=e,c[e]=w;
}
struct node{
	int id,dis;
	bool operator < (const node &A) const {
		return dis>A.dis;
	}
};
queue<int>q;
priority_queue<node>Q;
struct Dijkstra{
	int num,d[maxn];
	void dijkstra(){
		Q.push((node){num,0});
		for(int i=1;i<=n;i++)d[i]=inf;
		d[num]=0;
		while(!Q.empty()){
			node u=Q.top();Q.pop();
			if(u.dis>d[u.id])continue;
			for(int i=Begin[u.id];i;i=Next[i]){
				int v=to[i];
				if(d[v]>u.dis+c[i]){
					d[v]=u.dis+c[i];
					Q.push((node){v,d[v]});
				}
			}
		}
	}
}p[4];
void gett(int k,int u,int v,int w,int &t,bool &flag){
	int p1=p[k].d[u]+p[k+1].d[v];
	int p2=p[k+1].d[u]+p[k].d[v];
	if(p1<p2)t=p1+w,flag=0;
	else t=p2+w,flag=1;
}
int val[maxn],deg[maxn];
int solve(){
	int res=0;
	for(int i=1;i<=n;i++)
		if(!deg[i])q.push(i);
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int i=Begin[u];i;i=Next[i])
			if(is_ok[i]){
				int v=to[i];
				if(val[v]<val[u]+c[i]){
					val[v]=val[u]+c[i];
					if(res<val[v])res=val[v];
				}if(--deg[v]==0)q.push(v);
			}
	}
	return res;
}
int main(){
	int m,u,v,w;
	scanf("%d%d",&n,&m);
	for(int i=0;i<4;i++)
		scanf("%d",&p[i].num);
	while(m--){
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,w),add(v,u,w);
	}
	for(int i=0;i<4;i++)
		p[i].dijkstra();
	for(int i=1;i<=e;i+=2){
		bool flag1,flag2;
		int u=to[i+1],v=to[i],t1,t2;
		gett(0,u,v,c[i],t1,flag1);
		gett(2,u,v,c[i],t2,flag2);
		if((t1==p[0].d[p[1].num])&&(t2==p[2].d[p[3].num])){
			if(flag1==0)is_ok[i]=1,deg[v]++;
			else is_ok[i+1]=1,deg[u]++;
		}
	}
	printf("%d\n",solve());
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值