P1053Easy sssp
描述
输入数据给出一个有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的最短路的长度.
限制
Test5 5秒
其余 1秒
提示
做这道题时, 你不必为超时担心, 不必为不会算法担心, 但是如此“简单”的题目, 你究竟能ac么?
#include<cstdio> #include<iostream> #include<queue> #include<cstring> #define N 1010 #define M 100010 #define inf 9999999999999LL #define LL long long using namespace std; int head[N],in[N],n,m,s; LL dist[N],dis1[N]; struct node{ int v,next; long long w; }e[M]; bool flag,vis[N],use[N]; void add(int cnt,int x,int y,int z){ e[cnt].v=y; e[cnt].w=z; e[cnt].next=head[x]; head[x]=cnt; } void spfa(int so,LL dis[]){ queue<int>que; dis[so]=0; vis[so]=1; use[so]=1; in[so]++; que.push(so); while(!que.empty()){ int u=que.front();que.pop(); vis[u]=0; for(int i=head[u];i;i=e[i].next){ if(dis[e[i].v]>dis[u]+e[i].w){ dis[e[i].v]=dis[u]+e[i].w; if(!vis[e[i].v]){ vis[e[i].v]=1; use[e[i].v]=1; que.push(e[i].v); if(++in[e[i].v]>=n||dis[so]<0){ flag=1; return ; } } } } } } int main(){ //freopen("sh.txt","r",stdin); scanf("%d%d%d",&n,&m,&s); for(int i=1;i<=m;i++){ int x,y;LL z; scanf("%d%d%lld",&x,&y,&z); add(i,x,y,z); } fill(dist,dist+n+1,inf); for(int i=1;i<=n;i++){ if(use[i]) continue; if(flag){ puts("-1");return 0; } spfa(i,dis1); } spfa(s,dist); if(flag){ puts("-1");return 0; } for(int i=1;i<=n;i++){ if(dist[i]<inf) cout<<dist[i]<<endl; else printf("NoPath "); } return 0; }