POJ1860bellman-ford算法变形应用

正权回路:在这一回路上,顶点的权值能不断增加。即:能一直进行松弛,反向利用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;
}

猜你喜欢

转载自blog.csdn.net/qq_41658955/article/details/81538400