1. 程式人生 > >【洛谷】1821 [USACO07FEB]銀牛派對Silver Cow Party 最短路徑

【洛谷】1821 [USACO07FEB]銀牛派對Silver Cow Party 最短路徑

題目傳送門

日常水一波,就是對正向圖跑一遍SPFA,然後建一張反向圖,也就是求其他所有的節點到源點的距離,然後再跑一遍SPFA。

最後輸出兩次距離和的最大值就行了。

附上AC程式碼:

#include <cstdio>
#include <cctype>
#include <queue>
#include <cstring>
#define M 100010
#define N 1010
using namespace std;

struct note{
	int to,w,nt;
}z[M*2],f[M*2];
int n,m,st,num,hz[N],hf[N],x,y,w,d1[N],d2[N];
long long ans;
queue <int> que;
bool b[N];

void read(int& a){
	static char c=getchar();a=0;int f=1;
	while (!isdigit(c)) {if (c=='-') f=-1;c=getchar();}
	while (isdigit(c)) a=a*10+c-'0',c=getchar();
	a*=f;return;
}

void add(int x,int y,int w){
	z[num]=(note){x,w,hz[y]};
	f[num]=(note){y,w,hf[x]};
	hz[y]=hf[x]=num++;
}

void spfa1(){
	while (!que.empty()) que.pop();
	memset(b,0,sizeof b);
	memset(d1,0x3f,sizeof d1);
	que.push(st),d1[st]=0,b[st]=1;
	while (!que.empty()){
		int p=que.front();que.pop(),b[p]=0;
		for (int i=hz[p]; ~i; i=z[i].nt)
			if (d1[z[i].to]>d1[p]+z[i].w){
				d1[z[i].to]=d1[p]+z[i].w;
				if (!b[z[i].to]){
					b[z[i].to]=1;
					que.push(z[i].to);
				}
			}
	}
	return;
}

void spfa2(){
	while (!que.empty()) que.pop();
	memset(b,0,sizeof b);
	memset(d2,0x3f,sizeof d2);
	que.push(st),d2[st]=0,b[st]=1;
	while (!que.empty()){
		int p=que.front();que.pop(),b[p]=0;
		for (int i=hf[p]; ~i; i=f[i].nt)
			if (d2[f[i].to]>d2[p]+f[i].w){
				d2[f[i].to]=d2[p]+f[i].w;
				if (!b[f[i].to]){
					b[f[i].to]=1;
					que.push(f[i].to);
				}
			}
	}
	return;
}

int main(void){
	read(n),read(m),read(st);
	memset(hz,-1,sizeof hz),memset(hf,-1,sizeof hf);
	for (int i=1; i<=m; ++i) read(x),read(y),read(w),add(x,y,w);
	spfa1(),spfa2();
	for (int i=1; i<=n; ++i) ans=max(ans,(long long)d1[i]+d2[i]);
	printf("%lld",ans);
	return 0;
}