输入数据给出一个有N(2 <= N <= 1,000)个节点,M(M <= 100,000)条边的带权有向图.
要求你写一个程序, 判断这个有向图中是否存在负权回路. 如果从一个点沿着某条路径出发, 又回到了自己, 而且所经过的边上的权和小于0, 就说这条路是一个负权回路.
如果存在负权回路, 只输出一行-1;
如果不存在负权回路, 再求出一个点S(1 <= S <= N)到每个点的最短路的长度. 约定: S到S的距离为0, 如果S与这个点不连通, 则输出NoPath.
INPUT:
第一行: 点数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)
OUTPUT:
如果存在负权环, 只输出一行-1, 否则按以下格式输出
共N行, 第i行描述S点到点i的最短路:
如果S与i不连通, 输出NoPath;
如果i = S, 输出0;
其他情况输出S到i的最短路的长度
INPUT:
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
OUTPUT:
0
6
4
-3
-2
7
注意:
题目说的不是很清楚,给出的图不一定是完全联通图,有些是断开的几个图,所以在判断的源点是否有环以外还要分别对不同的点进行spfa呀。再进行分别的判断和输出。
有几个优化:
1.可以先判断是否有负权自环,有则直接输出-1
2.在枚举的过程中,当这个顶点的最短路(d[i])<0时,有负权回路,输出-1.
【参考程序】:
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
long queue[1001],a[1001],psum[1001],dis[1001],l[1001][1001],cost[1001][1001];
long n,m,s,i,j;
bool hash[1001],bk;
void spfa(int s)
{
int head,tail,start,now,i;
for (i=1;i<=n;i++)
{
dis[i]=0xfffffff;
psum[i]=0;
hash[i]=false;
}
head=tail=1;hash[s]=true;
psum[s]=1;dis[s]=0;queue[1]=s;
while (head<=tail)
{
start=queue[(head-1)%n+1];
hash[start]=true;
for (i=1;i<=l[start][0];i++)
{
now=l[start][i];
if (dis[now]>dis[start]+cost[start][now])
{
dis[now]=dis[start]+cost[start][now];
if (!hash[now])
{
hash[now]=true;
tail++;
queue[(tail-1)%n+1]=now;
psum[now]++;
if (psum[now]>n)
{//记录每个点进队的次数(判断环的关键}
bk=false;
return;
}
}
}
}
head++;
hash[start]=false;
if (dis[s]<0)
{//判断环的一个优化
bk=false;
return;
}
}
}
void output()
{
bk=true;
spfa(s);
if (!bk)
{
printf("-1/n");
return;
}
memcpy(a,dis,sizeof(long)*(n+1));
for (i=1;i<=n;i++)
if (a[i]==0xfffffff)
{
bk=true;
spfa(i);
if (!bk)
{
printf("-1/n");
return;
}
}
for (i=1;i<=n;i++)
if (a[i]==0xfffffff) printf("NoPath/n");
else printf("%d/n",a[i]);
}
void input()
{
scanf("%d%d%d",&n,&m,&s);
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
if (i==j) cost[i][j]=0;
else cost[i][j]=0xfffffff;
memset(l,0,sizeof(l));
int x,y,c;
for (i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&c);
if (c<cost[x][y])
{
cost[x][y]=c;
l[x][0]++;
l[x][l[x][0]]=y;
}
}
}
int main()
{
input();
output();
system("pause");
return 0;
}