poj 3259 Wormholes(SPFA || Bellman-Ford)

一直不想学这个算法。因为会了SPFA后,觉得SPFA既然是bellman-ford的优化,那就用SPFA吧。

 

遇到这个题。第一反应是floyd。结果TLE了 = =。看讨论,都是bellman或者SPFA,我就用SPFA了。结果不会判负环,因为之前做的最短路都是正值 = =。如果一个结点入队次数大于等于n说明存在负权回路。当时怎么也想不通。去上自习了。看物理看累了就模拟了下SPFA过程。。。很强大吧。。。加深了对SPFA的理解呢~

比如n个点(1到n),如果源点是1,去更新其他点,比如2点,如果其他点都能更新它,那它就入队n-1次了,这样按理来说已经松弛完毕了,但是如果继续入队,说明存在负权回路了。

 

 

后来看bellman-ford,觉得压力不大,SPFA的退化版,基本上,对每个边都进行n-1次松弛。

 

判断负环的时候只要看边还能不能再进行松弛了,如果能,说明负环了。

 

不过还是觉得应该先学bellman-ford再学SPFA。

 

Bellman-Ford

#include <stdio.h> #include <stdlib.h> #include <iostream> #include <string.h> #include <limits.h> #define SIZE 510 using namespace std; typedef struct rode{ int from,to,len; }rode; int cou; rode node[5210]; int n; void init() { memset(node,'/0',sizeof(node)); cou = 0; } int Bellman() { int dis[SIZE]; for(int i=1; i<=n; i++) dis[i] = INT_MAX; dis[1] = 0; for(int i=1; i<n; i++) { int over = 1; // 判断是否松弛完毕。。。 for(int k=0; k<cou; k++) { int from = node[k].from; int to = node[k].to; int len = node[k].len; if( dis[from] != INT_MAX && dis[to] > dis[from] + len )//得加前面的判断。要不就溢出了。 { dis[to] = dis[from] + len; over = 0; } } if( over ) break; } for(int i=0; i<cou; i++)// 判断是否有负权回路 { int from = node[i].from; int to = node[i].to; int len = node[i].len; if( dis[to] > dis[from] + len ) return 1; } return 0; } int main(void) { int ncases,from,to; int m,w,len; scanf("%d",&ncases); while( ncases-- ) { init(); scanf("%d%d%d",&n,&m,&w); for(int i=0; i<m; i++) { scanf("%d%d%d",&from,&to,&len); node[cou].from = from; node[cou].to = to; node[cou].len = len; cou++; node[cou].from = to; node[cou].to = from; node[cou].len = len; cou++; } for(int i=0; i<w; i++) { scanf("%d%d%d",&from,&to,&len); node[cou].from = from; node[cou].to = to; node[cou].len = -len; cou++; } if( Bellman() ) printf("YES/n"); else printf("NO/n"); } return 0; }  

 

 

SPFA

#include <stdio.h> #include <stdlib.h> #include <iostream> #include <string.h> #include <limits.h> #include <queue> #define SIZE 510 using namespace std; typedef struct rode{ int to,len; rode *next; }rode; queue<int> Q; int cou; rode node[30000],*p[SIZE]; int n; void init() { while( !Q.empty() ) Q.pop(); //因为多组数据,上一组可能在Q不为空的情况下已经退出,所以这里需要清空下。 memset(node,'/0',sizeof(node)); memset(p,'/0',sizeof(p)); cou = 0; } int SPFA() { int used[SIZE],dis[SIZE],num[SIZE]; rode *head[SIZE]; for(int i=1; i<=n; i++) { used[i] = 0; num[i]= 0; dis[i] = INT_MAX; head[i] = p[i]; } dis[1] = 0; used[1] = 1; num[1]++; Q.push(1); while( !Q.empty() ) { int x = Q.front(); Q.pop(); used[x] = 0; //需要反标记 head[x] = p[x]; while( head[x] != NULL ) { int to = head[x]->to; int len = head[x]->len; if( dis[to] > dis[x] + len ) { dis[to] = dis[x] + len; if( !used[to] ) { Q.push(to); used[to] = 1; num[to]++; if( num[to] >= n )// 学会的新知识= =..如果入队的次数超过总数,说明存在回路 return 1; } } head[x] = head[x] -> next; } } return 0; } int main(void) { int ncases,from,to; int m,w,len; scanf("%d",&ncases); while( ncases-- ) { init(); scanf("%d%d%d",&n,&m,&w); for(int i=0; i<m; i++) { scanf("%d%d%d",&from,&to,&len); node[cou].to = to; node[cou].len = len; node[cou].next = p[from]; p[from] = &node[cou]; cou++; node[cou].to = from; node[cou].len = len; node[cou].next = p[to]; p[to] = &node[cou]; cou++; } for(int i=0; i<w; i++) { scanf("%d%d%d",&from,&to,&len); node[cou].to = to; node[cou].len = -len; node[cou].next = p[from]; p[from] = &node[cou]; cou++; } if( SPFA() ) printf("YES/n"); else printf("NO/n"); } return 0; }  

你可能感兴趣的:(poj 3259 Wormholes(SPFA || Bellman-Ford))