首页 > 其他分享 >【差分约束】学习笔记

【差分约束】学习笔记

时间:2024-12-23 08:59:01浏览次数:4  
标签:head int 笔记 约束 vis edge 差分 dis

Basic Tips

差分约束,即为存在一个差分约束系统,即类似 \(x_i - x_j \leq k\) 的 \(n\) 元一次不等式组,求出一组解使得该组内所有不等式全部成立,即 \(x_1 = s_1,x_2 = s_2 \dots x_n = s_n\),否则判无解。

对于满足条件的一个解集 \(\{s_1,s_2,s_3,\dots,s_n\}\),集合 \(\{s_1 + t,s_2 + t,s_3 + t,\dots,s_n + t\}\) 也满足成为解集的条件。

为何用 spfa 求解?

名副其实,对于每一个不等式 \(x_i - x_j \leq k\),移项可得 \(x_i \leq x_j + k\),与 \(\text{spfa}\) 中的三角不等式极其相似,因此可以看做是 \(x_j\) 向 \(x_i\) 连了一条边权为 \(k\) 的有向边,然后就可以用 \(\text{spfa}\) 求解,若过程中存在负环则差分约束系统无解,否则对于 \(s_i = dis_i\) 即为差分约束系统的一个解。

注:\(\text{spfa}\) 跑最长路还是最短路的情况依据推出的差分约束系统不等式的形式,若为 \(x_i - x_j \leq k\),我们选择最短路,若 \(x_i - x_j \geq k\),我们选择最长路。

other

\(\text{spfa}\) 中的三角不等式 \(disv \geq dis_u + w\) 的解释。

如图:

\(v\) 为终点,\(u\) 为起点,\(v1\) 为中转点,显然,\(u \to v1 \to v\) 的路径是比 \(u \to v\) 的路径长的,因此 \(\text{spfa}\) 的过程可以看成对于每个点的出边做一次这样的操作。

example

P5960 【模板】差分约束

差分约束模板,根据上文所说的过程实现就行,需要注意的是,在没有保证建出的图联通时,需要从超级源点向每一条点连边。

code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN = 5e3 + 10;
int n,m,idx=1,head[MAXN << 1];
int dist[MAXN << 1],cnt[MAXN << 1];
bool vis[MAXN << 1];
struct node{
	int v,w,nxt;
}edge[MAXN << 1];
inline void add(int u,int v,int w){
	edge[idx].v = v;
	edge[idx].w = w;
	edge[idx].nxt = head[u];
	head[u] = idx ++;
}
inline bool spfa(int s){
	memset(cnt,0,sizeof cnt);
	memset(dist,-0x3f,sizeof dist);
	memset(vis,0,sizeof vis);
	queue<int>q;
	vis[s] = 1;
	dist[s] = 0;
	q.push(s);
	while(!q.empty()){
		int u = q.front();
		q.pop();
		vis[u] = 0;
		for(int i=head[u];i!=-1;i=edge[i].nxt){
			int v = edge[i].v,w = edge[i].w;
			if(dist[v] < dist[u] + w){
				dist[v] = dist[u] + w;
				if(!vis[v]){
					cnt[v] = cnt[u] + 1;
					if(cnt[v] > n + 1)
						return false;
					vis[v] = 1;
					q.push(v);
				}
			}
		}
	}
	return true;
}
signed main(){
	ios_base::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> m;
	memset(head,-1,sizeof head);
	for(int i=1;i<=m;i++){
		int u,v,w;
		cin >> u >> v >> w;
		add(u,v,-w);
	}
	for(int i=1;i<=n;i++)
		add(0,i,0);
	if(!spfa(0))
		cout << "NO" << endl;
	else{
		for(int i=1;i<=n;i++)
			cout << dist[i] << " ";
		cout << endl;
	}
	return 0;
} 

P4878 [USACO05DEC] Layout G

依据题目中给出的条件列出不等式 。

\( \begin{cases} x_i - x_j \leq d1 \\ x_k - x_p \geq d2 \end{cases} \)

然后建边,由于全图不保证联通,因此需要超级源点,从超级源点跑一次 \(\text{spfa}\) 判无解,另外从 \(1\) 号节点跑统计答案,由于题目中默认条件 \(x_i < x_j(i > j)\),需要将相邻两点连边。

code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int MAXN = 5e4 + 10;
const int inf = 1e9;
int n,m1,m2,idx = 1,head[MAXN],dis[MAXN],cnt[MAXN];
bool vis[MAXN];
struct node{
	int v,nxt,w;
}edge[MAXN];
inline void add(int u,int v,int w){
	edge[idx].v = v;
	edge[idx].w = w;
	edge[idx].nxt = head[u];
	head[u] = idx ++;
}
inline int spfa(int s){
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	memset(cnt,0,sizeof(cnt));
	queue<int>q;
	dis[s] = 0;
	vis[s] = 1;
	q.push(s);
	while(!q.empty()){
		int u = q.front();
		q.pop();
		vis[u] = 0;
		cnt[u] ++;
		if(cnt[u] > n)
			return -1;
		for(int i = head[u];i != -1;i = edge[i].nxt){
			int v = edge[i].v,w = edge[i].w;
			if(dis[v] > dis[u] + w){
				dis[v] = dis[u] + w;
				if(!vis[v]){
					vis[v] = 1;
					q.push(v);
				}
			}
		}
	}
	if(dis[n] > inf)
		return -2;
	return dis[n];
}
signed main(){
	memset(head,-1,sizeof(head));
	scanf("%lld %lld %lld",&n,&m1,&m2);
	for(int i = 1;i <= m1;i ++){
		int u,v,w;
		scanf("%lld %lld %lld",&u,&v,&w);
		add(u,v,w);
	}
	for(int i = 1;i <= m2;i ++){
		int u,v,w;
		scanf("%lld %lld %lld",&u,&v,&w);
		add(v,u,-w);
	}
	for(int i = 1;i <= n;i ++) add(0,i,0);
	for(int i = 1;i < n;i ++) add(i + 1,i,0);
	int tmp = spfa(0);
	if(tmp <= -1)
		printf("%lld\n",tmp);
	else
		printf("%lld\n",spfa(1));
	return 0;
}

习题

P1993 小 K 的农场

P4926 [1007] 倍杀测量者 利用对数的性质转化成差分约束系统

P2474 [SCOI2008] 天平

P3530 [POI2012] FES-Festival Tarjan 结合差分约束

[ABC087D] People on a Line

标签:head,int,笔记,约束,vis,edge,差分,dis
From: https://www.cnblogs.com/Ayaka-0928/p/18623001

相关文章

  • 【AI学习笔记4】四种主流的神经网络 FNN、RNN、CNN、Transformer
     一、人工神经网络的分类最常用的人工神经网络(ArtificialNeuralNetwork,ANN)主要包括以下四种:前馈神经网络(FeedforwardNeuralNetwork,FNN)、循环神经网络(RecurrentNeuralNetwork,RNN)和卷积神经网络(ConvolutionalNeuralNetwork,CNN),还有当前最流行的大模型常用的Transformer神......
  • 蓝桥杯——嵌入式学习笔记
    备战2025蓝桥杯嵌入式,记录一下过程。不定期更新,欢迎提出问题和指导。一、cubemx配置    1.芯片选择        嵌入式主板用的是STM32G431RBT系列,因此选择以下芯片    2.Pinout&Configuration        这里调整System......
  • INA226折腾笔记(一)
    其实也算不上折腾,这个模块很简单就一个简单的I2C模块。随便搞个单片机就能读写,之所以玩这个,主要还是对手上的USB表不满意(换句话说就是达不到我的需求)我手上有几个USB表左边那个高仿版FNB58,右边那个是科维斯的CC表型号为KWS-1902C,平时就是测测手机充电功率之类的,也够用,FNB58还带......
  • 8086汇编(16位汇编)学习笔记01.汇编基础和debug使用
    原文链接:https://bpsend.net/thread-100-1-2.html     为什么学习16位汇编?16位操作指令最多能够操作两个字节,且更能够体现出与硬件的交互。16位下的指令和32位汇编的指令差不多。16位汇编的指令在32位一样使用.要学好汇编必须要了解一点点硬件知识,16汇编是直接操作......
  • 【学习笔记】高位前缀和(SOSDP)
    高位前缀和解决这样的问题:给定\(f_i\),其中\(i\in[0,2^n-1]\),求解\(\sum\limits_{j\ini}f_j\)。考虑一维前缀和:for(inti=1;i<=n;i++){ sum[i]=sum[i-1]+a[i];}二位前缀和:for(inti=1;i<=n;i++){ for(intj=1;j<=n;j++){ sum[i][j]=sum[i][j-1]+a[i][j]; }}for......
  • 三维测量与建模笔记 - 7.2 点云滤波
        逐点计算法向量,需要对每一个点拟合出它的切平面,一般使用邻域点信息来查找切平面。    选取要计算的点和它周围一定范围内的点可以拟合出一个平面,最基本的方法是通过最小二乘法取对这些点到平面的距离进行优化(计算量很大)。可以通过计算协方差矩阵来实现......
  • 读书笔记:Redis5设计与源码分析
    Redis5设计与源码分析,陈雷本书赞誉序前言第1章引言11.1Redis简介1Redis由SalvatoreSanfilippo在2009年发布初始版本,开源后不断发展壮大。Redis优点:Redis的工作模式为单线程,不需要线程间的同步操作。Redis采用单线程主要因为其瓶颈在内存和带宽上,而不是CPU。1.2Re......
  • 2024/12月 读书笔记 - 7《构建之法》--- 第七章
    微软解决方案框架(MSF)概述本章将探讨微软公司推荐的软件开发方法——微软解决方案框架(MSF),它融合了多种软件开发方法论和原则,旨在指导微软的软件开发实践。MSF的核心原则开放沟通:确保所有信息透明共享,涉及所有相关角色,并公开决策过程。同时,对敏感信息如技术机密和安全性信息采取......
  • 2024/12月 读书笔记 - 8《构建之法》--- 第八章
    在软件开发过程中,准确捕捉和全面理解用户需求是至关重要的。以下是软件团队获取和处理需求的四个关键步骤:获取和引导需求:也称为“需求捕捉”,软件团队需要站在用户的角度思考,引导用户明确他们的需求。分析和定义需求:对收集到的需求进行整理和定义,从不同角度量化需求。验证需求:与......
  • 2024/12月 读书笔记 - 9《构建之法》--- 第九章
    在项目管理领域,不同公司对于项目管理角色的称呼有所不同。以下是几种常见的项目管理角色:ProductManager(PM):产品经理,负责确保产品正确地开发和实现。ProjectManager(PM):项目经理,负责确保项目流程正确地执行。ProgramManager:在微软,这个职位指的是负责特定项目或程序的经理......