【题解】狡猾的商人
一道有意思的差分约束,涨知识了。
题目地址:\(luogu\) \(P2294\)
看到这道题是不是感觉与差分约束一点关系没有啊。
分析一下从\(s\)月到\(t\)月的收入为\(c\)这句话。
注意是收入,它有累加的性质。也就是说:
\(sum[t]-sum[s-1]=c\),即前缀和。
那么我们如果以这一条为约束条件建图,就会发现一个差分约束的雏形。但是我们发现,这样是错的。
因为我们的约束条件不够。
从等式性质来看,显然还需要满足:\(sum_{s-1}-sum_t=-c\)
再建一条边即可。
继续考虑细节:起点从哪里来呢?
不用多想,图不一定连通的话,暴力遍历一遍所有点,对于没有访问过的点,再跑一遍\(Spfa\)即可。
\(Code:\)
#include<cstdio>
#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int MAXN=500000;
#define inf 0x3f
int T,n,m,head[MAXN],dis[MAXN],tot;
int vis[MAXN],cnt[MAXN],F=0;
queue<int>q;
struct edge{
int nxt,to,dis;
}e[MAXN];
inline void add(int x,int y,int w){
e[++tot].nxt=head[x];
e[tot].to=y;
e[tot].dis=w;
head[x]=tot;
}
bool SPFA(int s){
memset(dis,-inf,sizeof(dis));
dis[s]=0,q.push(s),vis[s]=1;
while(!q.empty()){
int k=q.front();
q.pop();vis[k]=0;
cnt[k]++;
if(cnt[k]>=n)return 0;
for(int i=head[k];i;i=e[i].nxt){
int j=e[i].to;
if(dis[j]<dis[k]+e[i].dis){
dis[j]=dis[k]+e[i].dis;
if(!vis[j])vis[j]=1,q.push(j);
}
}
}
return 1;
}
int main(){
scanf("%d",&T);
while(T--){
F=0;
scanf("%d%d",&n,&m);
memset(head,0,sizeof(head));
tot=0;memset(cnt,0,sizeof(cnt));
memset(vis,0,sizeof(vis));
for(int i=1;i<=m;++i){
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
//sum[b]-sum[a-1]=c,sum[a-1]-sum[b]=-c
add(a-1,b,c);add(b,a-1,-c);
}
for(int i=0;i<=n;++i)
if(!cnt[i])
if(!SPFA(i)){
F=1;
break;
}
if(!F)printf("true\n");
else printf("false\n");
}
return 0;
}