uva10806Dijkstra?Dijkstra?
每天刷6题的目标看来还是有点难啊~先找一道以前A掉的题目充数吧~不过个人觉得这题用SPFA真的不错的~(因为网络流我还不会o(╯□╰)o)
题意:有A,B两个人要越狱,A成功地从监狱到达火车站时B立即出发,两个人的路线不能有重合(可以重合点,不可以重合边),需要两个人路径和最短,求最短路径和。
抽象一点,就是找到从点S到T的最短长度的环(即:两次路径不能有重边)
思路:最大流的方法可以做,我用的是两次SPFA,相当于求两次最短路:先求一次最短路,然后把最短路上的S->T方向的边长赋值为INF,反向边长赋值为-map[u][v],即原来长度的相反数,然后再次SPFA,两次结果相加即可。
对于标记为反向长度取反,如果不懂,请看下图:
代码:
View Code
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <queue> 5 using namespace std; 6 const int MAXN = 100 + 5; 7 const int INF = 0x3f3f3f3f; 8 #define DEBUG 9 int map[MAXN][MAXN]; 10 int vis[MAXN], d[MAXN], fa[MAXN]; 11 void init(int n){ 12 int i, j; 13 for(i=1; i<=n; i++) 14 for(j=1; j<=n; j++) 15 if(i!=j) map[i][j]=INF; 16 else map[i][j]=0; 17 } 18 int SPFA(int S, int T, int n){ 19 int i; 20 memset(vis, 0, sizeof(vis)); 21 memset(d, 63, sizeof(d)); 22 d[S] = 0; 23 queue<int>q; 24 q.push(S); 25 vis[S]=1; 26 while(!q.empty()){ 27 int x=q.front(); 28 q.pop(); 29 vis[x]=0; 30 for(i=1; i<=n; i++) 31 if(d[i]>d[x]+map[x][i]){ 32 d[i]=d[x]+map[x][i]; 33 fa[i]=x; 34 if(!vis[i]){ 35 vis[i]=1; 36 q.push(i); 37 } 38 } 39 } 40 return d[T]; 41 } 42 int main(){ 43 #ifndef DEBUG 44 freopen("in.txt", "r", stdin); 45 #endif 46 int n, m; 47 while(scanf("%d", &n)!=EOF && n){ 48 scanf("%d", &m); 49 init(n); 50 int i, u, v, w; 51 for(i=1; i<=m; i++){ 52 scanf("%d%d%d", &u, &v, &w); 53 if(map[u][v]>w) map[u][v]=map[v][u]=w; 54 } 55 int S=1, T=n; 56 int ans1 = SPFA(S, T, n); 57 while(T!=S){ 58 map[T][fa[T]]=-map[T][fa[T]]; 59 map[fa[T]][T]=INF; 60 T=fa[T]; 61 } 62 T=n; 63 int ans2=SPFA(S, T, n); 64 if(ans1>=INF||ans2>=INF) printf("Back to jail\n"); 65 else printf("%d\n", ans1+ans2); 66 } 67 return 0; 68 }
Greatness is never a given, it must be earned.