Easy sssp

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次则存在负环。

  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\n"); 
103         else printf("%lld\n",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\n"); 
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 } 
View Code

 

转载于:https://www.cnblogs.com/fengzhiyuan/p/6977785.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值