图论之Bellman-Ford
First:
对于一个要参加noip的oier来说,图论是不得不涉及的一大考点,而其中有一个极其重要的算法,即Bellman-Ford。
作为图论入门课程中为数不多的可以针对负权回路的一种算法,Bellman-Ford无疑是迪杰斯特拉之外不得不牢牢掌握的另一算法。
Next:
Bellman-Ford是基于边的一种算法,所以当题目中的边数远小于点数时,即可考虑用边表存储稀疏图再用Bellman-Ford来解决问题。
Then:
那么Bellman-Ford的思想是什么的。
我们知道如果图中出现负权回路的话,迪杰斯特拉算法是错误的。这里需要不断迭代地做“松驰”,直到无“松驰”为止。
那么一个如何判断有没有出现负权回路呢?
由于每次循环都会枚举所有的边,所以每次至少会确定源点到一个点的最短路,这与迪杰斯特拉的思想相似,如此一来,最多只需要进行n-1次迭代即可完成最短路。
即(1)初始化每点到s点的最短距离为∞
(2)取所有边(x,y),看x能否对y松驰。
(3)如果没有任何松驰,则结束break。
(4)如果松驰次数
#include<bits/stdc++.h>
using namespace std;
struct bian
{
int q,h,v;
}a[7000];
long long d[7000];
bool flag=false;
int f;
int t=0;
int n,m,w;
bool bellman_ford(int st)
{
memset(d,10,sizeof(d));
d[st]=0;
for(int jj=1;jj<=n;++jj)
{
flag=0;
for(int jjj=1;jjj<=t;++jjj)
{
if(d[a[jjj].q]+a[jjj].v<d[a[jjj].h])
{
d[a[jjj].h]=d[a[jjj].q]+a[jjj].v;
flag=1;
}
}
if(!flag)
return false;
}
return true;
}
int main()
{
cin>>f;
for(int i=1;i<=f;++i)
{
cin>>n>>m>>w;
for(int j=1;j<=m;++j)
{
int x,y,z;
cin>>x>>y>>z;
a[++t].q=x;
a[t].h=y;
a[t].v=z;
a[++t].h=x;
a[t].q=y;
a[t].v=z;
}
for(int j=1;j<=w;++j)
{
int x,y,z;
cin>>x>>y>>z;
a[++t].q=x;
a[t].h=y;
a[t].v=-z;
}
if(bellman_ford(a[1].q))
{
cout<<"YES"<<endl;
}
else cout<<"NO"<<endl;
t=0;
}
return 0;
}