[bzoj1202][HNOI2005]狡猾的商人

t组数据。每次给你n,m,表示有n和m个条件,表示有n个整数,然后给出m个条件,每个条件有a,b,w,表示第a个到第b个的数的和w,你要判断每组数据的条件是否合法。t,n<=100,m<=1000

题解:把数组前缀和一下,然后对于每个条件,从a-1向b连权值为w的边,并且建出反边。然后求一下有没有两个点之间存在两种不同距离的路径就好啦。

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
    return x*f;
} 

struct edge{int next,to,w;}e[2005];
int q[101],top,tail,n,m,d[101],cnt,head[101];
bool b[101],yes;

inline void ins(int f,int t,int w){e[++cnt].next=head[f];head[f]=cnt;e[cnt].to=t;e[cnt].w=w;}

void solve(int from)
{
    b[from]=1;d[from]=0;top=tail=0;q[++top]=from;
    while(top!=tail)
    {
        int u=q[++tail];
        for(int i=head[u];i;i=e[i].next)
        {
            if(!b[e[i].to]){b[e[i].to]=1;d[e[i].to]=d[u]+e[i].w;q[++top]=e[i].to;}
            else if(d[e[i].to]!=d[u]+e[i].w){yes=false;return;}
        }    
    }
}

int main()
{
    int t=read();
    while(t--)
    {
        n=read();m=read();cnt=0;yes=true;
        memset(b,0,sizeof(b));memset(head,0,sizeof(head));
        for(int i=1;i<=m;i++)
        {int u=read(),v=read(),w=read();ins(u-1,v,w);ins(v,u-1,-w);}
        for(int i=0;i<=n&&yes;i++)if(!b[i]&&head[i])solve(i);
        puts(yes?"true":"false");
    }
    return 0;
}

 

posted @ 2017-03-15 19:11  FallDream  阅读(408)  评论(0编辑  收藏  举报