[BZOJ1880][Sdoi2009] Elaxia的路線 (最短路,拓撲排序)

這道題很不錯,要用最短路,建新圖,拓撲排序。


我一開始想的是求一遍floyd,找出兩個點 u,v,使得 dis[s][u]+dis[u][v]+dis[v][t]=dis[s][t],另一條路線也滿足着一個條件,找到最長的dis[u][v],但超時無疑,我就不會改了。


正解:

對4個點分別求一遍最短路,之後枚舉每一條邊 u-v,若dis1[u]+w+dis2[v]=dis1[t1],則這條邊在最短路上,如果另一條路也滿足這一條件,則這是兩條最短路的公共路線,就把他加入新圖中,最後在新圖中用拓撲排序求一下最長路.

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue> 
using namespace std;

inline void getint(int &x){
	x=0; int res=1; char c=getchar();
	while(!(c>='0'&&c<='9')){ if(c=='-') res=-1; c=getchar(); }
	while(c>='0' && c<='9') x=x*10+c-'0', c=getchar();
	x*=res;
} 

typedef long long LL;
const int N=1510, M=N*N;
const LL INF=100000000000000;
int n, m, mi, m2, x1, y1, x2, y2;
int head[N], h2[N], du[N];
LL s1[N], t1[N], s2[N], t2[N], tmp[N];
bool inq[N], vis[N];

queue <int> Q;

struct Edge{
	int to,next,w;
}e[N*N], e2[N*N];

inline void add(int u,int v,int w){
	e[++mi] = (Edge){v,head[u],w};
	head[u] = mi;
}

inline void add2(int u,int v,int w){
	du[v]++;
	e2[++m2] = (Edge){v,h2[u],w};
	h2[u] = m2;
}

inline void spfa(int s,LL *d){
	for(int i=1; i<=n; ++i) d[i]=INF, inq[i]=false;
	while(!Q.empty()) Q.pop();
	Q.push(s); d[s]=0;
	int u, v, p;
	while(!Q.empty()){
		u=Q.front(); Q.pop(); inq[u]=false;
		for(p=head[u]; p; p=e[p].next){
			v = e[p].to;
			if(d[v]>d[u]+e[p].w){
				d[v] = d[u]+e[p].w;
				if(!inq[v]){
					inq[v] = true;
					Q.push(v);
				}
			}
		}
	}
}

inline bool check(int u,int v,int w){
	return (s1[u]+(LL)w+t1[v]==s1[y1] && s2[u]+(LL)w+t2[v]==s2[y2])||(s1[u]+(LL)w+t1[v]==s1[y1] && s2[v]+(LL)w+t2[u]==s2[y2]);
}

inline LL topo(){
	LL ans=0;
	while(!Q.empty()) Q.pop();
	for(int i=1; i<=n; ++i) if(!du[i] && vis[i]) Q.push(i);
	int u, v, p;
	while(!Q.empty()){
		u=Q.front(); Q.pop();
		for(p=h2[u]; p; p=e2[p].next){
			v = e2[p].to; tmp[v] = max(tmp[v], tmp[u]+e2[p].w);
			if(!(--du[v])){
				Q.push(v);
				//tmp[v] = max(tmp[v], tmp[u]+e2[p].w);
			}
		}
	}
	for(int i=1; i<=n; ++i) ans=max(ans,tmp[i]);
	return ans;
}

int main(){
	scanf("%d%d%d%d%d%d",&n,&m,&x1,&y1,&x2,&y2);
	for(int i=1, u, v, w; i<=m; ++i){
		getint(u); getint(v); getint(w);
		add(u,v,w); add(v,u,w);
	}
	spfa(x1,s1); spfa(y1,t1); spfa(x2,s2); spfa(y2,t2);
	for(int u=1, p, v; u<=n; ++u){
		for(p=head[u]; p; p=e[p].next){
			v = e[p].to;
			if(check(u,v,e[p].w)){ vis[u]=vis[v]=true; add2(u,v,e[p].w); }
		}
	}
	printf("%lld\n",topo());
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章