农场派对
题目描述
N(1≤N≤1000)头牛要去参加一场在编号为x(1≤x≤N)的牛的农场举行的派对。有M(1≤M≤100000)条有向道路,每条路长Ti(1≤Ti≤100);每头牛都必须参加完派对后回到家,每头牛都会选择最短路径。求这N头牛的最短路径(一个来回)中最长的一条的长度。特别提醒:可能有权值不同的重边。
输入
第1行:3个空格分开的整数N,M,X;
第2…M+1行:3个空格分开的整数Ai,Bi,Ti,表示有一条从AiBi的路,长度为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
解题思路
牛牛的一个来回只需跑两趟spfa即可。第一遍spfa求出去农场的最短路,然后将边的方向调转(这里采用矩阵转置的方法),再跑一遍spfa即可得到回的最短路,相加便是一次来回的最短路径长度。
代码
#include<cstdio>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
#define MAXN 1005
#define INF 0x3f3f3f3f
int n,m,x;
int d[MAXN][MAXN], dis1[MAXN], dis2[MAXN];
bool vis[MAXN];
vector<int> edge[MAXN];
void init(void){
scanf("%d%d%d",&n,&m,&x);
for(int i=1;i<=n;++i){
for(int j=1;j<=n;++j) d[i][j] = INF;
d[i][i] = 0;
vis[i] = false;
dis1[i] = dis2[i] = INF;
}
for(int i=0;i<m;++i){
int a,b,t;
scanf("%d%d%d",&a,&b,&t);
if(d[a][b] > t) d[a][b] = t; //去重边,选择最短的边
}
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
if(i!=j && d[i][j]!=INF) edge[i].push_back(j);
}
void trans(void){ //矩阵转置
for(int i=1;i<=n;++i){
for(int j=1;j<i;++j){
int tmp = d[i][j];
d[i][j] = d[j][i];
d[j][i] = tmp;
}
}
for(int i=1;i<=n;++i) edge[i].clear();
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
if(i!=j && d[i][j]!=INF) edge[i].push_back(j);
}
void spfa(int u,int dis[]){ //dis采用参数传递,这样只需写一个spfa即可
dis[u] = 0; vis[u] = true;
queue<int> Q;
Q.push(u);
while(Q.size()){
int x = Q.front(); Q.pop();
vis[x] = false;
int len = edge[x].size();
for(int i=0;i<len;++i){
int y = edge[x][i], z = d[x][y];
if(dis[y] > dis[x]+z){
dis[y] = dis[x]+z;
if(!vis[y]) Q.push(y), vis[y] = true;
}
}
}
}
int main(void)
{
init();
spfa(x,dis1);
trans();
spfa(x,dis2);
int ans = 0;
for(int i=1;i<=n;++i) ans = max(ans,dis1[i]+dis2[i]);
printf("%d",ans);
return 0;
}