vijosP1053 Easy sssp
【思路】
SPFA。
题目中的陷阱比较多,但是只要中规中矩的写SPFA诸如:s与负圈不相连,有重边的情况都可以解决。
需要注意的有:
1、 数据d用long long
2、 如果没有负圈一个节点被更新的次数不会太多,将判断负圈达到改为n/2
跑两遍SPFA,一遍检查负圈,一遍求最短路即可。
【代码】
1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<iostream> 5 using namespace std; 6 7 typedef long long LL; 8 const int maxn = 1000+10 , maxm=100000+10; 9 const LL INF=1e15; 10 struct Edge{ 11 int v,w,next; 12 }e[maxm]; 13 int en=-1,front[maxn]; 14 15 int n,m,s; 16 17 inline void AddEdge(int u,int v,int w) { 18 en++; e[en].v=v; e[en].w=w; e[en].next=front[u]; front[u]=en; 19 } 20 21 LL d[maxn]; 22 bool SPFA(int s,int f) { 23 int inq[maxn],cnt[maxn]; 24 queue<int> q; 25 memset(inq,0,sizeof(inq)); 26 memset(cnt,0,sizeof(cnt)); 27 for(int i=1;i<=n;i++) d[i]=INF; 28 29 if(f==1) { 30 for(int i=1;i<=n;i++) { 31 d[i]=0; inq[i]=1; q.push(i); 32 } 33 } 34 else { 35 d[s]=0; inq[s]=1; q.push(s); 36 } 37 while(!q.empty()) { 38 int u=q.front(); q.pop(); inq[u]=0; 39 for(int i=front[u];i>=0;i=e[i].next) { 40 int v=e[i].v , w=e[i].w; 41 if(d[v]>d[u]+w) { 42 d[v]=d[u]+w; 43 if(!inq[v]) { 44 inq[v]=1; 45 q.push(v); 46 if(++cnt[v]>=(n/2)) return true; 47 //猥琐地只判断到n/2 48 } 49 } 50 } 51 } 52 return false; 53 } 54 55 int main() { 56 ios::sync_with_stdio(false); 57 memset(front,-1,sizeof(front)); 58 scanf("%d%d%d",&n,&m,&s); 59 int u,v,w; 60 for(int i=0;i<m;i++) { 61 scanf("%d%d%d",&u,&v,&w); 62 AddEdge(u,v,w); 63 } 64 if(SPFA(0,1)) printf("-1 "); 65 else 66 { 67 SPFA(s,2); 68 for(int i=1;i<=n;i++) 69 if(d[i]>=INF) printf("NoPath "); 70 else printf("%lld ",d[i]); 71 } 72 return 0; 73 }