其他分享
首页 > 其他分享> > P2294 [HNOI2005]狡猾的商人

P2294 [HNOI2005]狡猾的商人

作者:互联网

一句话题意:


给出一堆三元组 \((u, v, w)\),意思是 \(v\) 到 \(u\) 这一块的和正好为 \(w\),求问这一堆三元组是否满足互相不冲突。


考虑去用前缀和维护,那么三元组就转化成了以下这个等式:

\[sum_v-sum_u=w \]

将它拆分成两个不等式:

\[sum_v-sum_u\le=w,\ sum_v-sum_u\ge=w \]

把两个不等式转成同号的就可以用差分约束做了,记得多测清空。

#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <queue>
#define N 500005
using namespace std;
inline int read(){
	char ch;int x=0, f=1;ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*f;
}
int tot, h[N];
struct Edge{
	int to, nxt, v;
}edge[N*3];
void add(int x, int y, int w){
	edge[++tot].to=y, edge[tot].nxt=h[x];
	edge[tot].v=w, h[x]=tot;
}
int n, m;
int dis[N], in[N], cnt[N];
bool SPFA(int s){
	queue <int> q;
	memset(dis, 0x3f, sizeof(dis));
	q.push(s);dis[s]=0;cnt[s]=1;
	while(!q.empty()){
		int x=q.front();q.pop(), in[x]=0;
//		printf("--%d %d\n", x, dis[x]);
		for(int i=h[x]; i; i=edge[i].nxt){
			int to=edge[i].to, w=edge[i].v;
			if(dis[to]>dis[x]+w){
				dis[to]=dis[x]+w;
				if(!in[to]){
					in[to]=1, cnt[to]++;
					if(cnt[to]>=n+2) return 0;
					q.push(to);
				}
			}
		}
	}
	return 1;
}
int main(){
	int T=read();
	for(; T; T--){
		n=read(), m=read();
		tot=0;//多测清空 
		memset(h, 0, sizeof(h));
		memset(cnt, 0, sizeof(cnt));
		memset(in, 0, sizeof(in));
		//sum[l-1]-sum[r]<=-w
		//sum[r]-sum[l-1]<=w
		for(int i=1; i<=n; i++) add(n+1, i, 0);
		//超级源点 
		for(int i=1; i<=m; i++){
			int l=read(), r=read(), w=read();
			add(r, l-1, -w);add(l-1, r, w);
		}
		if(SPFA(n+1)) printf("true\n");
		else printf("false\n");
	} 
	return 0;
} 

标签:cnt,ch,int,sum,memset,HNOI2005,狡猾,P2294,dis
来源: https://www.cnblogs.com/sizeof127/p/14615895.html