【题解】狡猾的商人

一道有意思的差分约束,涨知识了。

题目地址:\(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;
} 
posted @ 2019-08-15 20:54  Refined_heart  阅读(197)  评论(0编辑  收藏  举报