差分约束 [HNOI2005]狡猾的商人(洛谷 P2294)

[HNOI2005]狡猾的商人

题目大意:

n 个月,m 个约束条件,判断最终是否产生矛盾;


因为这里不是 x i x_i xi <= y j y_j yj + c k c_k ck,而是 s u m t sum_t sumt- s u m s − 1 sum_{s-1} sums1 = v i v_i vi,所以单向连边并不满足条件,要正反双向连边,然后求最短路,判断是否有负环;

代码:

#include
#define LL long long
#define pa pair
#define ls k<<1
#define rs k<<1|1
#define inf 0x3f3f3f3f
using namespace std;
const int N=20100;
const int M=50100;
const int mod=1e9;
int n,m;
struct Node{
	int to,nex,w;
}edge[N*2];
int head[N],cnt,dis[N],vis[N],sum[N];
void add(int p,int q,int w){
	edge[cnt].w=w,edge[cnt].to=q,edge[cnt].nex=head[p],head[p]=cnt++;
}
bool spfa(){
	for(int i=0;i<=n+1;i++) dis[i]=2e9,sum[i]=0,vis[i]=0;
	dis[0]=0;
	queue<int>qu;qu.push(0);
	while(!qu.empty()){
		int p=qu.front();qu.pop();
		vis[p]=0;sum[p]++;
		if(sum[p]>=n) return false;
		for(int i=head[p];~i;i=edge[i].nex){
			int q=edge[i].to;
			if(dis[q]>dis[p]+edge[i].w){
				dis[q]=dis[p]+edge[i].w;
				if(!vis[q]) qu.push(q),vis[q]=1;
			}
		}
	}
	return true;
}
void init(){
	memset(head,-1,sizeof(head));
	cnt=0;
	for(int i=0;i<=2*m;i++) edge[i].nex=edge[i].to=edge[i].w=0;
}
int main(){
	int w;scanf("%d",&w);
	while(w--){
		scanf("%d%d",&n,&m);
		init();
		for(int i=1;i<=m;i++){
			int s,t,v;scanf("%d%d%d",&s,&t,&v);
			add(s,t+1,v),add(t+1,s,-v);
		}
		for(int i=1;i<=n+1;i++) add(0,i,0);
		if(!spfa()) printf("false\n");
		else printf("true\n");
	}
	return 0;
}

你可能感兴趣的:(#,差分约束,差分约束)