vijos:P1053Easy sssp(spfa判环)
生活随笔
收集整理的這篇文章主要介紹了
vijos:P1053Easy sssp(spfa判环)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
描述
輸入數據給出一個有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
思路:spfa算法,不過這道題存在陷阱。第一存在重邊,解決方法用鄰接矩陣表示圖,保留權值最小的一個。第二圖可能不連通,解決方法對每個結點進行spfa,為了優化時間,設置一個used數組標志已經遍歷過的結點,遍歷過的結點無需再進行spfa。最后加上若d[s]<0則存在負環。
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int MAXN=1005;
const int INF=0x7f7f7f7f;
int n,m,s;
int contain;
int mp[MAXN][MAXN];
int d[MAXN];
int cnt[MAXN];
bool vis[MAXN],used[MAXN];
void addedge(int u,int v,int w)
{
if(mp[u][v]>w)
mp[u][v]=w;
}
bool spfa(int scource)
{
for(int i=1;i<=n;i++)
{
d[i]=INF;
vis[i]=false;
}
queue<int> que;
que.push(scource);
vis[scource]=true;
used[scource]=true;
d[scource]=0;
while(!que.empty())
{
int now = que.front();que.pop();
vis[now]=false;
for(int i=1;i<=n;i++)
{
if(now==i||mp[now][i]==INF) continue;
if(d[i]>d[now]+mp[now][i])
{
d[i]=d[now]+mp[now][i];
if(d[scource]<0) return true;
if(!vis[i])
{
used[i]=vis[i]=true;
que.push(i);
cnt[i]++;
if(cnt[i]>=n) return true;
}
}
}
}
return false;
}
void solve()
{
for(int i=1;i<=n;i++)
{
if(!used[i]&&spfa(i))
{
printf("-1
");
return ;
}
}
if(spfa(s))
{
printf("-1
");
}
else
{
for(int i=1;i<=n;i++)
if(d[i]==INF) printf("NoPath
");
else printf("%d
",d[i]);
}
}
int main()
{
scanf("%d%d%d",&n,&m,&s);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(i==j) mp[i][j]=0;
else mp[i][j]=mp[j][i]=INF;
for(int i=0;i<m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
}
solve();
return 0;
}
spfa+前向星可解決重邊問題。d[source][source]<0則存在負環
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int MAXN=1005;
const int INF=0x3f3f3f3f;
struct Edge{
int to,w,next;
}es[100005];
int head[MAXN],tot;
int n,m,source;
int d[MAXN][MAXN],vis[MAXN],used[MAXN];
void addedge(int u,int v,int w)
{
es[tot].to=v;
es[tot].w=w;
es[tot].next=head[u];
head[u]=tot++;
}
bool spfa(int s)
{
for(int i=1;i<=n;i++)
{
d[s][i]=INF;
vis[i]=0;
}
queue<int> que;
que.push(s);
d[s][s]=0;
vis[s]=1;
used[s]=1;
while(!que.empty())
{
int u=que.front();que.pop();
vis[u]=0;
for(int i=head[u];i!=-1;i=es[i].next)
{
Edge e=es[i];
if(d[s][e.to]>d[s][u]+e.w)
{
d[s][e.to]=d[s][u]+e.w;
if(d[s][s]<0) return true;
if(!vis[e.to])
{
que.push(e.to);
vis[e.to]=1;
used[e.to]=1;
}
}
}
}
return false;
}
void solve()
{
if(spfa(source))
{
printf("-1
");
return ;
}
for(int i=1;i<=n;i++)
{
if(!used[i]&&spfa(i))
{
printf("-1
");
return ;
}
}
for(int i=1;i<=n;i++)
{
if(d[source][i]==INF) printf("NoPath
");
else printf("%d
",d[source][i]);
}
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%d%d%d",&n,&m,&source);
for(int i=0;i<m;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
}
solve();
return 0;
}
總結
以上是生活随笔為你收集整理的vijos:P1053Easy sssp(spfa判环)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Tomcat启动设置环境变量
- 下一篇: Thrift入门及Java实例演示