首页 > 其他分享 >差分约束 + 01BFS

差分约束 + 01BFS

时间:2024-11-29 18:11:54浏览次数:10  
标签:le emplace int 差分 约束 vis 01BFS dis

属于简单知识点的补档。

差分约束

差分约束系统 是一种特殊的 \(n\) 元一次不等式组,包含 \(n\) 个变量 \(x_1,\dots,x_n\) 和 \(m\) 个约束条件,每个约束条件形如 \(x_i-x_j\le c_k\),其中 \(c_k\) 是常数。我们要解决的问题是求出 \(x_1,\dots,x_n\) 的一组解。

差分约束问题是最短路算法的一种巧妙应用。我们发现,差分约束系统中的每个约束条件 \(x_i-x_j\le c_k\) 都可以变形成 \(x_i\le x_j+c_k\),这不由得让我们想到单源最短路中的三角形不等式 \(\text{dis}(v)\le\text{dis}(u)+w\)。因此,我们把每个未知数 \(x_i\) 看作图中的一个节点,对每一个约束条件 \(x_i-x_j\le c_k\) 连边。

连边方法有两种:

  1. 连一条 \(x_j\to x_i\) 的边权为 \(c_k\) 的边之后跑最短路,最终求出来的解是 \(x_i\le0\) 时所有 \(x\) 的最大值
  2. 连一条 \(x_i\to x_j\) 的边权为 \(-c_k\) 的边之后跑最长路,最终求出来的解是 \(x_i\ge0\) 时所有 \(x\) 的最小值

这两种方法不能混用。

注意这样连完边之后图不一定联通,此时我们只需定义一个 “超级源点” \(0\),并对所有 \(i\) 连 \((0,i,0)\) 的边。然后,跑最短/最长路。

至于题目中要求判断无解,我们只需用 SPFA 判断是否存在负环即可。若存在负环,则无解;否则,\(x_i=\text{dis}(i)\) 就是题目要求的一组解。

例 1 P5960 【模板】差分约束

constexpr int MAXN=5005;
int n,m,head[MAXN],tot;
struct{
	int v,to,w;
}e[MAXN<<1];
void addedge(int u,int v,int w){
	e[++tot]={v,head[u],w};
	head[u]=tot;
}
int dis[MAXN],cnt[MAXN];
bool vis[MAXN];
queue<int>q;
void spfa(){
	memset(dis,0x3f,sizeof(int)*(n+5));
	dis[0]=0;
	vis[0]=1;
	q.emplace(0);
	while(!q.empty()){
		int u=q.front();
		q.pop();
		vis[u]=0;
		for(int i=head[u];i;i=e[i].to)
			if(dis[e[i].v]>dis[u]+e[i].w){
				dis[e[i].v]=dis[u]+e[i].w;
				if(!vis[e[i].v]){
					vis[e[i].v]=1;
					q.emplace(e[i].v);
					if(++cnt[e[i].v]>n){
						puts("NO");
						exit(0);
					}
				}
			}
	}
}

int main(){
	n=read(),m=read();
	for(int i=1,u,v,w;i<=m;++i){
		u=read(),v=read(),w=read();
		addedge(v,u,w);
	}
	for(int i=1;i<=n;++i) addedge(0,i,0);
	spfa();
	for(int i=1;i<=n;++i) write(dis[i],' ');
	return putchar('\n'),fw,0;
}

例 2 P1993 小 K 的农场

把所有不等式转化为标准形式即可。注意连边方法一定一定不能弄混。

#include<bits/stdc++.h>
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
using namespace std;

char buf[1<<20],*p1=buf,*p2=buf;
int read(){
	int x=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x;
}
constexpr int MAXN=5005;
int n,m,head[MAXN],tot;
struct{
	int v,to,w;
}e[MAXN<<1];
void addedge(int u,int v,int w){
	e[++tot]={v,head[u],w};
	head[u]=tot;
}
int dis[MAXN],cnt[MAXN];
bool vis[MAXN];
queue<int>q;
void spfa(){
	memset(dis,0x3f,sizeof(int)*(n+5));
	dis[0]=0;
	vis[0]=1;
	q.emplace(0);
	while(!q.empty()){
		int u=q.front();
		q.pop();
		vis[u]=0;
		for(int i=head[u];i;i=e[i].to)
			if(dis[e[i].v]>dis[u]+e[i].w){
				dis[e[i].v]=dis[u]+e[i].w;
				if(!vis[e[i].v]){
					vis[e[i].v]=1;
					q.emplace(e[i].v);
					if(++cnt[e[i].v]>=n){
						puts("No");
						exit(0);
					}
				}
			}
	}
}

int main(){
	n=read(),m=read();
	for(int i=1,op,u,v;i<=m;++i){
		op=read(),u=read(),v=read();
		switch(op){
			case 1: addedge(u,v,-read());break;
			case 2: addedge(v,u,read());break;
			case 3: addedge(u,v,0),addedge(v,u,0);break;
		}
	}
	for(int i=1;i<=n;++i) addedge(0,i,0);
	spfa();
	return puts("Yes"),0;
}

01BFS

01BFS 用于解决边权只有 \(0\) 和 \(1\) 的最短路问题,复杂度是 \(O(n+m)\) 的,可以避免一般最短路算法的 \(\log\)。

方法:用一个双端队列 deque,把边权为 \(0\) 的边放到队首,边权为 \(1\) 的边放到队尾。

[AGC056C] 01 Balanced

这道题的主要部分在这篇题解里。这里只放它的 01BFS 部分。

void bfs(){
	memset(dis,-1,sizeof(int)*(n+5));
	dis[0]=0;
	deque<int>q;
	q.emplace_back(0);
	while(!q.empty()){
		int u=q.front();
		q.pop_front();
		for(int i=head[u];i;i=e[i].to){
			if(~dis[e[i].v]) continue;
			dis[e[i].v]=dis[u]+e[i].w;
			e[i].w?q.emplace_back(e[i].v):q.emplace_front(e[i].v);
		}
	}
}

标签:le,emplace,int,差分,约束,vis,01BFS,dis
From: https://www.cnblogs.com/laoshan-plus/p/18577300

相关文章

  • 蓝桥2128 重新排序(差分)
    给定一个数组A和一些查询Li和Ri,求数组第Li个至第Ri个元素之和。小蓝觉得这个问题很无聊,于是他想重新排列一下数组,使得最终每个查询结果的和尽可能地大。小蓝想知道相比原数组,所有查询结果的总和最多可以增加多少?大致思路:m次查询,每次求Li至Ri之和,我们可以用差分统计每个位......
  • mysql约束
    #创建一个表#需求:id为主键,并自增;name不能为空,且不可重复;age年龄在0-120之间;status状态默认为1,gender性别要求无createtableperson(idintprimarykeyauto_incrementcomment'主键',namevarchar(10)notnulluniquecomment'名字',ageintche......
  • 元器件选型与参数11 运算放大器各类电路-直流电压 电流检测、交流耦合与直流叠加、反
    目录一、直流电压、直流电流检测1、电压检测2、电流检测二、交流耦合与直流的叠加1、交流耦合2、同相直流叠加3、跨阻-反相直流叠加4、基准源的提供5、差分放大器-基准源一、直流电压、直流电流检测1、电压检测    通过对输入电压进行电阻分压,从而得到与......
  • 基础算法——前缀和、差分 学习笔记
    前缀和及差分前缀和一维前缀和定义一维前缀和,就是数组前若干项的和。我们对于前缀和数组的定义非常广泛,例如定义\(S(x)\)表示数组\(A(x)\)的前缀和,定义\(A(l,r)\)表示\(A(l)+A(l+1)+\dots+A(r)\),\(S(x)=A(0,x)\);\(S(x)=A(1,x)\);\(S(x)=A(1,x-1)\);\(S(x)......
  • 多智能体系统的约束驱动最优控制:高速公路车队案例研究(Matlab代码实现)
      ......
  • 差分约束系统
    差分约束给出\(n\)个活动,设\(t_i\)表示第\(i\)个活动开始的时间。这些活动满足以下\(m\)个类似关系:\[\begin{cases}t_{i1}-t_{j1}<=B_1\\t_{i2}-t_{j2}<=B_2\\\dots\\t_{im}-t_{jm}<=B_m\end{cases}\]其中\(1<=i_1,i_2,\dots,i_m,j_1,j_2,\dots,j_m<=n\)求满......
  • C++20中的Concepts 与 Java/C#中的范型约束
    C++20中的Concepts与Java/C#中的范型约束大家好!最近对C++20中的Concepts非常上头,上一篇聊了C++20中的Concepts与TypeScript,那么今天,就索性连Java和C#中的相似特性一起聊了算了。C++20引入了概念(Concepts),它是一种用来对模板参数进行约束的机制,能够提升模板编程的类型安......
  • [MySQL]第六章:MySQL表的约束
    本专栏内容为:MySQL学习专栏......
  • FPGA时序约束基础
    一、时序约束的目的由于实际信号在FPGA内部期间传输时,由于触发器等逻辑期间并非理想期间,因此不可避免地存在传输延时,这种延迟在高速工作频率、高逻辑级数时会造成后级触发器地建立时间和保持时间不满足,造成时序违例。(这也是为什么需要把FPGA设计不能以高级编程语言思想看的原因,设......
  • 【采用BPSK或GMSK的Turbo码】MSK、GMSK调制二比特差分解调、turbo+BPSK、turbo+GMSK研
      ......