正权回路:在这一回路上,顶点的权值能不断增加。即:能一直进行松弛,反向利用bellman-ford算法
原始的bellman-ford可以用来判负圈,现在我们改进一下用来判定有没有正权回路
反向利用bellman算法求正权回路初始化时,dis[x]=0(x!=s),s为源点,无论是判负圈还是判正圈,最终都是利用bellman算法松弛n-1次后能不能继续松弛来判定,松弛的方向:判负圈向减小的方向松弛,判正圈向增加的方向松弛
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=105;
double dis[maxn];//用来为顶点存放结果
int u[maxn<<1][2];//用来存放边的两端顶点
//两端顶点调换位置,属于不同的边
//这道题属于无向图
double c[maxn<<1][2];//0表示佣金,1表示汇率
int n,m,s;
double v;
void init()
{
memset(dis,0,sizeof(dis));
dis[s]=v;
}
bool bellman_ford()//1表示能增加有正权回路
{
for(int i=1; i<n; i++)
{
int flag=1;
for(int j=0; j<2*m; j++)
{
//从pp->qq
int pp=u[j][0];
int qq=u[j][1];
if(dis[qq]<(dis[pp]-c[j][0])*c[j][1])
{
dis[qq]=(dis[pp]-c[j][0])*c[j][1];
flag=0;
}
}
if(flag)
return false;//更新完成,没有正权回路
}
for(int j=0; j<2*m; j++)
{
int pp=u[j][0];
int qq=u[j][1];
if(dis[qq]<(dis[pp]-c[j][0])*c[j][1])
return true;//依然可以进行松弛操作
//说明有正权回路存在
}
return false;//有可能正好n-1次更新完成
}
int main()
{
int a,b;
double c0,c1,d0,d1;
while(~scanf("%d%d%d%lf",&n,&m,&s,&v))
{
init();
for(int i=0; i<m; i++)
{
scanf("%d%d%lf%lf%lf%lf",&a,&b,&c0,&c1,&d0,&d1);
u[i<<1][0]=a;
u[i<<1][1]=b;
c[i<<1][1]=c0;//汇率
c[i<<1][0]=c1;
u[i<<1|1][0]=b;
u[i<<1|1][1]=a;
c[i<<1|1][1]=d0;//汇率
c[i<<1|1][0]=d1;
}
if(bellman_ford())
printf("YES\n");
else
printf("NO\n");
}
return 0;
}