P2294 [HNOI2005]狡猾的商人(差分约束)

P2294 [HNOI2005]狡猾的商人

对于每个$(x,y,w)$,连边$(x-1,y,w),(y,x-1,-w)$,表示前$y$个月的收益比前$x-1$个月的收益大$w$

这样题目就转化为询问图中是否有非零环存在

于是我们找找正环(最长路)和负环(最短路)就好了


你发现其实正环和负环是等价的

所以你只要求其中一个就行了

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define N 105
int T,n,m,a[N][N],f1[N],f2[N],inf;
bool vis1[N],vis2[N],ok;
void spfa1(int x){
    if(vis1[x]) ok=1;
    if(ok) return ;
    vis1[x]=1;
    for(int i=0;i<=n&&!ok;++i)
        if(a[x][i]!=inf)
            if(f1[i]>f1[x]+a[x][i])
                f1[i]=f1[x]+a[x][i],spfa1(i);
    vis1[x]=0;
}
void spfa2(int x){
    if(vis2[x]) ok=1;
    if(ok) return ;
    vis2[x]=1;
    for(int i=0;i<=n&&!ok;++i)
        if(a[x][i]!=inf)
            if(f2[i]<f2[x]+a[x][i])
                f2[i]=f2[x]+a[x][i],spfa2(i);
    vis2[x]=0;
}
int main(){
    scanf("%d",&T);
    while(T--){
        memset(a,127,sizeof(a)); inf=a[0][0];
        memset(f1,127,sizeof(f1));
        memset(f2,128,sizeof(f2));
        scanf("%d%d",&n,&m); ok=0; f1[0]=f2[0]=0;
        for(int i=1,u,v,w;i<=m;++i){
            scanf("%d%d%d",&u,&v,&w);
            a[u-1][v]=w;
            a[v][u-1]=-w;
        }
        for(int i=0;i<=n;++i) spfa1(i),spfa2(i);//自选一种
        puts(ok?"false":"true");
    }return 0;
}

 

posted @ 2019-10-22 12:28  kafuuchino  阅读(199)  评论(0编辑  收藏  举报