P2294 [HNOI2005]狡猾的商人


P2294 [HNOI2005]狡猾的商人
题目描述

输入格式:
从文件input.txt中读入数据,文件第一行为一个正整数w,其中w < 100,表示有w组数据,即w个账本,需要你判断。每组数据的第一行为两个正整数n和m,其中n < 100,m < 1000,分别表示对应的账本记录了多少个月的收入情况以及偷看了多少次账本。接下来的m行表示刁姹偷看m次账本后记住的m条信息,每条信息占一行,有三个整数s,t和v,表示从第s个月到第t个月(包含第t个月)的总收入为v,这里假设s总是小于等于t。

输出格式:
输出文件output.txt中包含w行,每行是true或false,其中第i行为true当且仅当第i组数据,即第i个账本不是假的;第i行为false当且仅当第i组数据,即第i个账本是假的。

输入输出样例

输入样例#1:
2
3 3
1 2 10
1 3 -5
3 3 -15
5 3
1 5 100
3 5 50
1 2 51
输出样例#1:
true
false
这题利用解和每月的值得唯一性来构造差分约束系统,再利用每月金钱的累积构造前缀和即可构造成一个如v<=f[t]-f[s-1]<=v;再将其转化为差分约束的一般式,形如{f[t]-f[s-1]<=v;f[t]-f[s-1]>=v};再将下式进行转化为f[s-1]-f[t]<=-v;再从s-1向t构造一条边权为v,从t向s-1构造一条边权为-v的边,最后只需判断负环,来判断矛盾即可,因为若无矛盾最后边权相互抵消,值为非负数,若形成负环则证明结果有误,输出false;
#include<bits/stdc++.h>
using namespace std;
struct zz{int nx,to,d;}e[2090];
int h[230],v[230],ans[230],nm;
void add(int x,int y,int d)
{
e[++nm].nx=h[x];
e[nm].to=y;
e[nm].d=d;
h[x]=nm;
}
bool zx(int x)//深搜判负环,效率更高
{
v[x]=1;
for(int i=h[x];i!=-1;i=e[i].nx)
{
if(ans[x]+e[i].d<ans[e[i].to])
{
ans[e[i].to]=ans[x]+e[i].d;
if(v[e[i].to]||zx(e[i].to))
{
v[e[i].to]=0;
return 1;
}
}
}
v[x]=0;
return 0;
}
string bjt()
{
int m,n,s,t,p;
nm=0;
scanf("%d%d",&n,&m);
memset(h,-1,sizeof(h));
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&s,&t,&p);
add(s-1,t,p);//建边
add(t,s-1,-p);
}
for(int i=0;i<=n;i++)
{
memset(v,0,sizeof(v));
memset(ans,0,sizeof(ans));
if(zx(i))//判断负环
return "false";
}
return "true";
}
int main()
{
int w;
scanf("%d",&w);
for(int i=1;i<=w;i++)
cout<<bjt()<<endl;
return 0;
}

猜你喜欢

转载自www.cnblogs.com/LWL--Figthing/p/9108888.html