题目大意:
有限输入的数据N,M,X。N表示有N个农场,每个农场有一头奶牛;M表示连接这N个农场的M条边(有向边),X表示农场的一个编号(1,2,...,n)。
现在每个农场的牛都要走到编号为X的农场上去(选择最短路走),并返回自己的农场(选择最短路走),要求输出这些n头牛走的路程中(去+回的路程和)的最大值。
解题思路:
一个很简单的最短路径问题,用两次dijkstra算法就可以了,还要用到了矩阵的转置。首先用一次dijkstra算法(求编号为X的农场到其他农场的最短距离),求出每个农场的牛到X农场的最短距离。然后将矩阵(保存有向路径的信息)转置,在用一次dijkstra算法(求编号为X的农场到其他农场的最短距离),也就是求出了每头牛返回自己农场的最短距离。
如果不进行矩阵的转置,对于没有牛都用到一次dijkstra算法,那么时间复杂度就会增加,会出现超时。所以,在求每头牛返回的最短路径中,进行一次矩阵的转置,是把所有的有向边改变方向,只需一次dijkstra算法就可以了。
代码:
#include<cstdio>
#include<cstring>
#define Max 100000
#define M 1005
int time[M],a[M][M],dis[M],vis[M];
int n,m,x;
void dijkstra(int v){
int i,j,u;
for(int i=0;i<n;i++){
dis[i]=a[v][i];
vis[i]=0;
}
int min;
vis[v]=1;
for(i=1;i<n;i++){
min=Max;u=-1;
for(j=0;j<n;j++){
if(vis[j]==0 && dis[j]<min){
u=j;min=dis[j];
}
}
vis[u]=1;
for(j=0;j<n;j++){
if(vis[j]==0 && dis[j]>dis[u]+a[u][j]){
dis[j]=dis[u]+a[u][j];
}
}
}
return ;
}
int main(){
int f,t,c;
while(~scanf("%d%d%d",&n,&m,&x)){
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(i==j){
a[i][j]=0;
continue;
}
a[i][j]=Max;
}
}
for(int i=0;i<m;i++){
scanf("%d%d%d",&f,&t,&c);
a[f-1][t-1]=c;
}
//memset(vis,0,sizeof(vis));
memset(time,0,sizeof(time));
dijkstra(x-1);
for(int i=0;i<n;i++){ //去时的最短时间
time[i]=dis[i];
}
for(int i=0;i<n;i++){ //矩阵转置
for(int j=i+1;j<n;j++){
int tmp;
tmp=a[i][j];
a[i][j]=a[j][i];
a[j][i]=tmp;
}
}
dijkstra(x-1);
for(int i=0;i<n;i++){ //返回时的最短时间
time[i]+=dis[i];
}
int max=0;
for(int i=0;i<n;i++){
if(max<time[i])
max=time[i];
}
printf("%d\n",max);
}
return 0;
}