首页 > 编程语言 >[算法学习笔记] 差分约束

[算法学习笔记] 差分约束

时间:2024-03-16 15:11:06浏览次数:17  
标签:le dist 不等式 int 短路 笔记 leq 算法 差分

Description

一个差分约束系统是这样的。

给定一组包含 \(m\) 个不等式,有 \(n\) 个不等式形如:

\[\begin{cases} x_{c_1}-x_{c'_1}\leq y_1 \\x_{c_2}-x_{c'_2} \leq y_2 \\ \cdots\\ x_{c_m} - x_{c'_m}\leq y_m\end{cases} \]

求任意一组可行解。

Solution

观察这个式子:

\(x_{c1}-x_{c'1} \le y_1\)

我们将这个式子移项,得:

\(x_{c1}\le y_1+x_{c'1}\)

观察到这个式子类似于求最短路中的松弛操作。我们可以将 \(x_{c'1}\) 到 \(x_{c1}\) 连一条长度为 \(y_1\) 的边。然后跑最短路即可。

至于从哪个点开始跑呢?实际上我们从任意一个点开始跑都可以。但是很多情况我们得到的图都是不连通的。因此我们习惯上人为添加一个超级源点。

也就是从 \(0\) 号节点向每一个点连一条长度为 \(0\) 的边。也就是人为添加了以下约束条件:

\[\begin{cases} x_{c_1}-x_{0}\leq 0 \\x_{c_2}-x_{0} \leq 0 \\ \cdots\\ x_{c_m} - x_{0}\leq 0\end{cases} \]

注意到此时所有点的最短路都 \(\le 0\)。如果我们想要非负解呢?

这也很简单,根据不等式的基本性质,将所有满足约束的 \(x_i\) 同加上一个值,仍然满足约束。我们只需要在超级源点连边的时候赋为 \(w\) 即可。

这样我们得到的就是 \(\forall x_i \le w\) 的一组解。事实上,可以证明这是满足 \(\forall x_i \le w\) 的最大解。

那么如何求最小解呢?只需要求最长路即可。

对于判定无解,我们只需要在求最短路的时候判负环即可。如果出现负环,则最短路无解,显然不等式组无解。

题目中有时给出的不等式组并非差分约束系统一般形式,我们可以通过一系列转换。灵活应用转换为朴素查分约束系统。

模板代码

#include <bits/stdc++.h>
using namespace std;
typedef pair<int,int> PAIR;
const int N = 100010;
const int INF = 0x3f3f3f3f;
int vis[N];
int dist[N];
int cnt[N];
vector <PAIR> Edge[N];
int n,m;
bool spfa()
{
	queue <int> q;
	q.push(0);
	vis[0] = 1;
	dist[0] = 0;
	while(!q.empty())
	{
		int u = q.front();
	//	cout<<cnt[u]<<endl;
		if(cnt[u] >= n)
		{
			return false;
		}
		q.pop();
		vis[u] = 0;
		for(auto v:Edge[u])
		{
			int vv = v.first,ww = v.second;
			if(dist[vv] > dist[u] + ww)
			{
				cnt[vv] ++;
				//cout<<cnt[u]<<endl;
				dist[vv] = dist[u] + ww;
				if(!vis[vv]) q.push(vv);
			}
		}
	}
	return true;
}
int main()
{
//	freopen("input.txt","r",stdin);
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>m;
	for(int i=1;i<=m;i++)
	{
		int v,u,w;
		cin>>v>>u>>w;
		Edge[u].push_back({v,w});	
	} 
	for(int i=1;i<=n;i++) Edge[0].push_back({i,0});
	for(int i=1;i<=n;i++) dist[i] = INF;
	if(!spfa()) 
	{
		cout<<"NO"<<endl;
		return 0;
	}
	for(int i=1;i<=n;i++) cout<<dist[i]<<" ";
	cout<<endl;
	return 0;
}

标签:le,dist,不等式,int,短路,笔记,leq,算法,差分
From: https://www.cnblogs.com/SXqwq/p/18077096

相关文章

  • C++算法学习心得八.动态规划算法(3)
    1.最后一块石头的重量II(1049题)题目描述:有一堆石头,每块石头的重量都是正整数。每一回合,从中选出任意两块石头,然后将它们一起粉碎。假设石头的重量分别为 x和 y,且 x<=y。那么粉碎的可能结果如下:如果 x==y,那么两块石头都会被完全粉碎;如果 x!=y,那么重量为 x 的......
  • 代码随想录算法训练营day24 | leetcode 77. 组合
    目录题目链接:77.组合题目链接:77.组合题目描述:给定两个整数n和k,返回范围[1,n]中所有可能的k个数的组合。你可以按任何顺序返回答案。示例1:输入:n=4,k=2输出:[[2,4],[3,4],[2,3],[1,2],[1,3],[1,4],]示例2:输入:n=1,k=1输出:[[1]......
  • 3.2_3 页面置换算法
    3.2_3页面置换算法  请求分页存储管理与基本分页存储管理的主要区别:  在程序执行过程中,当所访问的信息不在内存时,由操作系统负责将所需信息从外存调入内存,然后继续执行程序。  若内存空间不够,由操作系统负责将内存中暂时用不到的信息换出到外存。  页面置换算......
  • 搜索与回溯算法
    排列#include<cstdio>#include<iostream>#include<algorithm>#include<iomanip>intvis[25],ans[25];intn;usingnamespacestd;voiddfs(intdep){if(dep==n+1){for(inti=1;i<=n;i++)cout<<setw(......
  • Java学习笔记——第十七天
    File、IO流(一)为什么要有文件存储数据的方案变量、数组、内存和集合它们都是内存中的数据容器,这些数据在断电或程序终止时会丢失。文件文件是非常重要的存储方式。它们存储在计算机硬盘中,即便断电,或者程序终止了,存储在硬盘文件中的数据也不会丢失。File和IO流概述FileFil......
  • 【NVIDIA JETSON AGX XAVIER】与个人笔记本(win11)建立TCP-IP连接相互传输数据(含源码)
    文章目录前言一、个人笔记本(win11)传输数据到XAVIER(多次传输)1.服务器端代码(个人笔记本win11)2.客户端代码(NVIDIAJETSONAGXXAVIER)二、两端相互传输(以另一种形式解决上一篇博客的问题)1.服务器端代码(个人笔记本win11)2.客户端代码(NVIDIAJETSONAGXXAVIER)三、传输数据中......
  • 代码随想录算法训练营第十一天| 20. 有效的括号 1047. 删除字符串中的所有相邻重复
    20.有效的括号https://leetcode.cn/problems/valid-parentheses/description/publicbooleanisValid(Strings){if(s==null)returntrue;Stack<Character>stack=newStack<>();for(inti=0;i<s.length();i++){......
  • 滴水逆向笔记系列-c++总结2-36.权限控制-37.虚函数-38.多态_绑定
    第三十六课c++3权限控制1.定义和实现分开写2.private和publicprivate权限说明私有变量在类外是无法访问的,只有在类内或者使用类内函数访问类内函数访问3.private真的不能访问吗反汇编看看t对象在初始化public和private成员时都是一视同仁的,在底层还是没区别,都是编......
  • 滴水逆向笔记系列-c++总结3-39.模板-40.引用_友元_运算符重载
    第三十八课c++6模板1.冒泡排序和折半查找voidSort(int*arr,intnLength) { inti; intk; for(i=0;i<nLength-1;i++) { for(k=0;k<nLength-1-i;k++) { if(arr[k]>arr[k+1]) { inttemp=arr[k]; a......
  • 滴水逆向笔记系列-c++总结4-41.new-delete-vector-42.链表
    第四十课c++8new-delete-vector1.内存空间复习在类外函数外的变量就是全局变量,程序一编译地址就已经确定了的临时数据,参数和局部变量就是在堆栈里而使用malloc函数动态申请的则是在堆里2.跟踪调试反汇编函数我们调用malloc函数申请内存,但是不是malloc一个函数完成整个......