题目链接:https://vjudge.net/problem/POJ-3268
解题思路:
各牛从 $X$ 回家的最短路很容易求,用 $Dijkstra$ 求 $X$ 到各点的单源最短路即可。难点在于求各牛从家到 $X$ 点的最短路,因为路是单向的,所以往返的最短路未必相等。在这点有一个很巧妙的解决思路:把已知的各单向路倒置,权值不变,再用一次 $Dijkstra$,此时的X到各点的单源最短路其实就是各点到X的最短路。
AC代码:
1 #include <iostream> 2 #include <cstdio> 3 using namespace std; 4 int len[1005][1005],dlen[1005][1005]; 5 int vis[1005],d[1005],dvis[1005],dd[1005]; 6 const int INF=1e8; 7 int main() 8 { 9 int N,M,X; 10 scanf("%d%d%d",&N,&M,&X); 11 for(int i=1;i<=N;i++){ 12 for(int j=1;j<=N;j++){ 13 if(i==j) len[i][j]=len[j][i]=dlen[i][j]=dlen[j][i]=0; 14 else len[i][j]=len[j][i]=dlen[i][j]=dlen[j][i]=INF; 15 } 16 d[i]=dd[i]=INF; 17 } 18 d[X]=dd[X]=0; 19 while(M--){ 20 int a,b,t; 21 scanf("%d%d%d",&a,&b,&t); 22 len[a][b]=dlen[b][a]=t; 23 } 24 while(1){ 25 int v=-1; 26 for(int u=1;u<=N;u++){ 27 if(!vis[u] && (v==-1||d[u]<d[v])) v=u; 28 } 29 if(v==-1) break; 30 vis[v]=1; 31 for(int u=1;u<=N;u++) 32 d[u]=min(d[u],d[v]+len[v][u]); 33 } 34 while(1){ 35 int v=-1; 36 for(int u=1;u<=N;u++){ 37 if(!dvis[u] && (v==-1||dd[u]<dd[v])) v=u; 38 } 39 if(v==-1) break; 40 dvis[v]=1; 41 for(int u=1;u<=N;u++) 42 dd[u]=min(dd[u],dd[v]+dlen[v][u]); 43 } 44 int ans=0; 45 for(int i=1;i<=N;i++){ 46 if(dd[i]+d[i]>ans) 47 ans=dd[i]+d[i]; 48 } 49 printf("%d\n",ans); 50 51 return 0; 52 }