1. 程式人生 > >【題解:POJ3268 Silver Cow Party】(最短路問題)

【題解:POJ3268 Silver Cow Party】(最短路問題)

傳送門:(http://poj.org/problem?id=3268)
題目描述:
農場有N(1≤N≤1000)個牛棚,每個牛棚都有1只奶牛要參加在X牛棚舉行的奶牛派對.共有M(1≤M≤100000)條單向路連線著牛棚,第i條踣需要Ti的時間來通過.牛們都很懶,所以不管是前去X牛棚參加派對還是返回住所,她們都採用了用時最少的路線.那麼,用時最多的奶牛需要多少時間來回呢?

輸入
第1行:三個用空格隔開的整數n,m,x. 第2行到第M+1行,每行三個用空格隔開的整數:Ai, Bi,以及Ti.表示一條道路的起點,終點和需要花費的時間.

輸出
唯一一行:一個整數: 所有參加聚會的奶牛中,需要花費總時間的最大值.

樣例輸入
4 8 2
1 2 4
1 3 2
1 4 7
2 1 1
2 3 5
3 1 2
3 4 4
4 2 3
樣例輸出
10

讀完題很容易發現這是一道最短路問題,只需找到節點i—>節點x的最短路,再找到節點x—>節點i的最短路,兩次spfa的結果相加就可得到節點i總共需要的時間,最後排序或者打擂臺就OK了
x到i的距離很好求,直接spfa就好,關鍵是i到x的距離
難道是做n次最短路,分別求出i到x的最短路?動動腳指頭上角質層的最外面的那一小塊,也知道不行啊。

還是那句老話啊,正難則反,正難則反,正難則反。

既然每一次spfa都是以x為終點的,那為何不反向建圖,做一個以x為起點的單源最短路呢?

所以流程就很清楚了。
step1:讀入
step2:建圖,注意建兩次,一次正向一次反向,也就是建兩張圖。
step3:兩次spfa,在原圖中找到奶牛返程所需的時間,在返圖中找到奶牛出程所需的時間。
step4:1~n跑一遍,求出每頭奶牛的總耗時,然後排序(或打擂臺)。
step5:輸出。
貼程式碼:

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstring>
#include<cstdio>
using namespace std;
inline int read(){
	int ans,flag=1;
	char ch;
	while((ch=getchar())<'0'||ch>'9') if(ch=='-') flag=-1;
	ans=ch-48;
	while((ch=getchar())>='0'&&ch<='9') ans=ans*10+ch-48;
	return ans*flag;
}
int n,m,x;
int vis[3][1001],dis[3][1001];
int head[1001],Head[1001],cnt=0,num=0;
int ans[1001];
struct node{
	int u,v,w,nt;
}e[1000001],E[1000001];
inline void add1(int u,int v,int w){
	cnt++;
	e[cnt].u=u,e[cnt].v=v,e[cnt].w=w;
	e[cnt].nt=head[u],head[u]=cnt;
}
inline void add2(int u,int v,int w){
	num++;
	E[num].u=u,E[num].v=v,E[num].w=w;
	E[num].nt=Head[u],Head[u]=num;
}
void spfa1(int x){
	memset(vis[1],0,sizeof(vis[1]));
	memset(dis[1],0x3f,sizeof(dis[1]));
	dis[1][x]=0;vis[1][x]=1;
	queue<int> q;
	q.push(x);
	while(!q.empty()){
		int u=q.front();q.pop();
		vis[1][u]=0;
		for(int i=head[u];i;i=e[i].nt){
			int v=e[i].v;
			if(dis[1][v]>dis[1][u]+e[i].w){
				dis[1][v]=dis[1][u]+e[i].w;
				if(!vis[1][v]) q.push(v) ,vis[1][v]=1;
			}
		}
			
	}
}
void spfa2(int x){
	memset(vis[2],0,sizeof(vis[2]));
	memset(dis[2],0x3f,sizeof(dis[2]));
	dis[2][x]=0;vis[2][x]=1;
	queue<int> q;
	q.push(x);
	while(!q.empty()){
		int u=q.front();q.pop();
		vis[2][u]=0;
		for(int i=Head[u];i;i=E[i].nt){
			int v=E[i].v;
			if(dis[2][v]>dis[2][u]+E[i].w){
				dis[2][v]=dis[2][u]+E[i].w;
				//cout<<
				if(!vis[2][v]) 
				{
					q.push(v) ,vis[2][v]=1;
				}
			}
		}
			
	}
}
int main(){
	n=read(),m=read(),x=read();
	int u,v,w;
	while(m--){
		u=read(),v=read(),w=read();
		add1(v,u,w);
		add2(u,v,w);
	}
	spfa1(x),spfa2(x);
	for(int i=1;i<=n;i++) ans[i]=dis[1][i]+dis[2][i];
	int ret=-1;
	for(int i=1;i<=n;i++) if(ans[i]>ret) ret=ans[i];
	cout<<ret;
	//cout<<ret<<" "<<id<<endl;
	//cout<<dis[1][id]<<" "<<dis[2][id];
	return 0;
}