糖果-差分约束

本文探讨了糖果分配问题的解决策略,通过构建差分约束图并应用SPFA算法求解,确保每个节点(人)的糖果数满足特定条件下的最小化目标。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

糖果-差分约束

题目描述

题目描述

题解

典型的差分约束;
我们不妨假设边u→vu→vuv表示的是vvvuuu大多少,贪心的想到要使得最后的糖果数最小,就尽可能的使得相连的两点糖果数差值尽可能的小(一定是以两者间小的为标准,相等时差为000,否则大的数比小的至少大111),最后的糖果总数显然最大。

于是我们针对这5种情况分别建边(以下出现的siz[x]siz[x]siz[x]表示的是xxx的糖果数):
  1、当条件为siz[u]==siz[v]siz[u]==siz[v]siz[u]==siz[v],则建边w[u,v]=0;w[v,u]=0w[u,v]=0;w[v,u]=0w[u,v]=0;w[v,u]=0表示siz[u]==siz[v]siz[u]==siz[v]siz[u]==siz[v]
  2、当条件为siz[u]<siz[v]siz[u]<siz[v]siz[u]<siz[v],若u==vu==vu==v则直接输出−1−11(显然不成立),否则建边w[u,v]=1w[u,v]=1w[u,v]=1(表示siz[v]比siz[u]大1siz[v]比siz[u]大1siz[v]siz[u]1
  3、当条件为siz[u]>=siz[v]siz[u]>=siz[v]siz[u]>=siz[v],则建边w[v,u]=0w[v,u]=0w[v,u]=0(表示siz[u]==siz[v]siz[u]==siz[v]siz[u]==siz[v],注意方向v→uv→uvu,因为要保证最优性,就必须从小的向大的转移,尽可能的让大的和小的相等)
  4、当条件为siz[u]>siz[v]siz[u]>siz[v]siz[u]>siz[v],若u==vu==vu==v则直接输出−1−11(显然不成立),否则建边w[v,u]=1w[v,u]=1w[v,u]=1(表示siz[u]比siz[v]大1siz[u]比siz[v]大1siz[u]siz[v]1
  5、当条件为siz[u]<=siz[v]siz[u]<=siz[v]siz[u]<=siz[v],则建边w[u,v]=0w[u,v]=0w[u,v]=0(表示siz[v]==siz[u]siz[v]==siz[u]siz[v]==siz[u],注意方向u→vu→vuv,因为要保证最优性,就必须从小的向大的转移,尽可能的让大的和小的相等
  接着,新建一个000节点作为源点,向i=1 ni=1~ni=1 n所有点都连边w[0,i]=1w[0,i]=1w[0,i]=1(表示每个点至少有1个糖果)(倒序建边,否则spfaspfaspfaTTT)
  然后,我们跑一遍最长路

代码实现

#include<bits/stdc++.h>//差分约束 
#define M 200009
using namespace std;
int nxt[M],first[M],w[M],to[M],tot;
int n,m,vis[M],cnt[M];
long long ans,d[M];
inline int read(){
	int f=1,re=0;
	char ch;
	for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
	if(ch=='-'){f=-1,ch=getchar();}
	for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
	return re*f; 
}
inline void add(int x,int y,int z){
	nxt[++tot]=first[x];
	first[x]=tot;
	to[tot]=y;
	w[tot]=z;
}
inline void spfa(){
	vis[0]=1,d[0]=0;
	queue<int>q;
	q.push(0);
	while(q.size()){
		int u=q.front();
		q.pop(),vis[u]=0;
		if(cnt[u]==n-1){printf("-1\n"),exit(0);}
		cnt[u]++;
		for(register int i=first[u];i;i=nxt[i]){
			int v=to[i];
			if(d[v]<d[u]+w[i]){
				d[v]=d[u]+w[i];
				if(!vis[v]) q.push(v),vis[v]=1;
			}
		}
	}
}
int main(){
	int type,x,y;
	n=read(),m=read();
	for(register int i=1;i<=m;i++){
		type=read(),x=read(),y=read();
		if(type%2==0&&x==y) return !printf("-1\n");
		if(type==1) add(x,y,0),add(y,x,0);
		if(type==2) add(x,y,1);
		if(type==3) add(y,x,0);
		if(type==4)	add(y,x,1);
		if(type==5) add(x,y,0);
	}for(register int i=n;i>=1;i--) add(0,i,1);
	spfa();
	for(register int i=1;i<=n;i++) ans+=d[i];
	printf("%lld\n",ans);
	return 0; 
}

做题启发

1,对于卡spfa的题,可以考虑倒序建边。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值