P2294 [HNOI2005]狡猾的商人
(来自Luogu)
题目概述
数据规模:
w,n,m <= 100
思路:
这个题的难点在于不好想到差分,转化:a-b=k是a-b>=k&&a-b<=k的充要条件, 这样就是建双向边,我们这次用至多型,就是ADD(B,A-1,K),ADD(A-1,B,-K),这里A-1的原因是利用了前缀和的思想,毕竟在这里权值是最短路的值,然后DFS_SPFA判负环,这样就可以判定正误了。
代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
using namespace std;
int i,j,l,m,n,temp;
int y[50001],hd[50001],nxt[50001],v[50001];
int b[50001],d[50001];
int r()
{
int aans=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
aans*=10;
aans+=ch-'0';
ch=getchar();
}
return aans*f;
}
void add(int xx,int yy,int zz)
{
nxt[++temp]=hd[xx];
y[temp]=yy;
v[temp]=zz;
hd[xx]=temp;
}
int dfs(int x)
{
b[x]=1;
for(int i=hd[x]; i; i=nxt[i])
{
if(d[x]+v[i]<d[y[i]])
{
d[y[i]]=d[x]+v[i];
if(!b[y[i]])
{
if(!dfs(y[i]))
return 0;
}
else
return 0;
}
}
b[x]=0;
return 1;
}
int main()
{
int tt;
tt=r();
while(tt)
{
tt--;
memset(d,0x7f7f7f,sizeof(d));
memset(hd,0,sizeof(hd));
memset(y,0,sizeof(y));
memset(v,0,sizeof(v));
memset(nxt,0,sizeof(nxt));
memset(b,0,sizeof(b));
temp=0;
n=r(),m=r();
int xx,yy,zz;
// for(i=1; i<=n; i++)
// {
// add(0,i,0);
// }
for(i=1; i<=m; i++)
{
xx=r(),yy=r(),zz=r();
add(xx-1,yy,-zz);
add(yy,xx-1,zz);
}
d[0]=0;
if(!dfs(0))
cout<<"false"<<endl;
else
cout<<"true"<<endl;
}
return 0;
}
/*
3 3
1 1 2 1
1 2 3 1
1 3 1 1
*/