Easy sssp
时间限制: 1 Sec 内存限制: 128 MB提交: 103 解决: 20
[提交][状态][讨论版]
题目描述
输入数据给出一个有N(2 < = N < = 1,000)个节点,M(M < = 100,000)条边的带权有向图. 要求你写一个程序, 判断这个有向图中是否存在负权回路. 如果从一个点沿着某条路径出发, 又回到了自己, 而且所经过的边上的权和小于0, 就说这条路是一个负权回路. 如果存在负权回路, 只输出一行-1; 如果不存在负权回路, 再求出一个点S(1 < = S < = N)到每个点的最短路的长度. 约定: S到S的距离为0, 如果S与这个点不连通, 则输出NoPath.
输入
第一行: 点数N(2 < = N < = 1,000), 边数M(M < = 100,000), 源点S(1 < = S < = N); 以下M行, 每行三个整数a, b, c表示点a, b(1 < = a, b < = N)之间连有一条边, 权值为c(-1,000,000 < = c < = 1,000,000)
输出
如果存在负权环, 只输出一行-1, 否则按以下格式输出 共N行, 第i行描述S点到点i的最短路: 如果S与i不连通, 输出NoPath; 如果i = S, 输出0; 其他情况输出S到i的最短路的长度.
样例输入
6 8 1 1 3 4 1 2 6 3 4 -7 6 4 2 2 4 5 3 6 3 4 5 1 3 5 4
样例输出
0 6 4 -3 -2 7
提示
做这道题时, 你不必为超时担心, 不必为不会算法担心, 但是如此“简单”的题目, 你究竟能ac么?
题解:这是一道spfa的题目吧,考点是spfa的应用和spfa判断负权回路的问题,每个块都判断一次,若其中有一个块存在负权回路,则直接输出NoPath;如果不存在,则输出最短路即可。
spfa判断负环应该都知道吧,一个点如果进栈n次则存在负环。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 #include<iostream> 5 #include<string> 6 #include<cstring> 7 8 using namespace std; 9 const int MAXN=1007,MAXM=100007; 10 11 int num,first[MAXN],next[MAXM],arr[MAXM],cost[MAXM]; 12 int times[MAXN]; 13 int n,m,st; 14 int p[MAXN]; 15 bool boo[MAXN],he[MAXN]; 16 long long dis[MAXN]; 17 18 void add(int u,int v,int z) 19 { 20 num++; 21 next[num]=first[u]; 22 first[u]=num; 23 arr[num]=v; 24 cost[num]=z; 25 } 26 void init() 27 { 28 memset(he,0,sizeof(he)); 29 memset(times,0,sizeof(times)); 30 memset(boo,0,sizeof(boo)); 31 memset(next,0,sizeof(next)); 32 memset(arr,0,sizeof(arr)); 33 memset(cost,0,sizeof(cost)); 34 for (int i=1;i<=n;i++) 35 first[i]=-1; 36 num=0; 37 for (int i=1;i<=n;i++) 38 dis[i]=100000007; 39 dis[st]=0; 40 } 41 bool pan(int st) 42 { 43 int head=0,tail=1; 44 p[tail]=st,boo[st]=1; 45 times[st]++; 46 47 while (head!=tail) 48 { 49 head=head%n+1; 50 int u=p[head],v; 51 for (int i=first[u];i!=-1;i=next[i]) 52 { 53 v=arr[i]; 54 if (dis[u]+cost[i]<dis[v]) 55 { 56 dis[v]=dis[u]+cost[i]; 57 if (boo[v]==0) 58 { 59 times[v]++; 60 if (times[v]>=n) 61 { 62 return 1; 63 } 64 boo[v]=1; 65 tail=tail%n+1; 66 p[tail]=v; 67 } 68 } 69 } 70 boo[u]=0; 71 } 72 for (int i=1;i<=n;i++) 73 if (dis[i]<100000007) he[i]=1; 74 return 0; 75 } 76 void solve(int st) 77 { 78 int head=0,tail=1; 79 p[tail]=st,boo[st]=1; 80 81 while (head!=tail) 82 { 83 head=head%n+1; 84 int u=p[head],v; 85 for (int i=first[u];i!=-1;i=next[i]) 86 { 87 v=arr[i]; 88 if (dis[u]+cost[i]<dis[v]) 89 { 90 dis[v]=dis[u]+cost[i]; 91 if (boo[v]==0) 92 { 93 boo[v]=1; 94 tail=tail%n+1; 95 p[tail]=v; 96 } 97 } 98 } 99 boo[u]=0; 100 } 101 for (int i=1;i<=n;i++) 102 if (dis[i]==100000007) printf("NoPath "); 103 else printf("%lld ",dis[i]); 104 } 105 int main() 106 { 107 scanf("%d%d%d",&n,&m,&st); 108 init(); 109 110 int x,y,z; 111 for (int i=1;i<=m;i++) 112 { 113 scanf("%d%d%d",&x,&y,&z); 114 add(x,y,z); 115 } 116 for (int i=1;i<=n;i++) 117 if (he[i]==0) 118 { 119 for (int i=1;i<=n;i++) 120 dis[i]=100000007; 121 dis[i]=0; 122 if (pan(i)) 123 { 124 printf("-1 "); 125 return 0; 126 } 127 memset(boo,0,sizeof(boo)); 128 memset(times,0,sizeof(times)); 129 } 130 for (int i=1;i<=n;i++) 131 dis[i]=100000007; 132 dis[st]=0; 133 solve(st); 134 }