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

差分约束学习笔记

时间:2023-05-06 11:11:08浏览次数:47  
标签:le int 短路 笔记 约束 差分 dis

2023.5.6 写的太烂了重新写

差分约束系统

定义

差分约束系统是一种特殊的 \(n\) 元一次不等式组,它包含 \(n\) 个变量 \(x_{1},x_{2},...,x_{n}\) 以及 \(m\) 个约束条件,每一个约束条件都是两个其中的变量做差构成的,形如 \(x_{i}-x_{j}\le c_{k}\),其中 \(1\le i,j\le n,i\ne j,1\le k\le m\) 并且 \(c_{k}\) 是常数(可以为正数或非正数)。
------- OI Wiki

通俗一点讲,这类问题都是给定 \(n\) 个变量,\(m\) 个限制,类似于:

\[\left\{\begin{matrix} op_{1}:x_{1}-x_{2}=c_{1}\\ op_{2}:x_{4}-x_{n}=c_{2}\\ ......\\ op_{m}:x_{n}-x_{3}=c_{m} \end{matrix}\right. \]

有了这些条件,一般的题目会让你求出一组合法的解,也就是求这 \(n\) 个变量的合法的值。

过程

我们可以建一个超级源点,然后向每一个点连一条边权为 \(0\) 的边,然后跑单源最短路;而上面的 \(m\) 个限制都可以变形为 \(x_{i}\le x_{j}+c_{k}\),这个东西很容易想到我们在跑最短路的时候的松弛操作里的 \(dis[v]\le dis[u]+w\),因此我们就可以把每一个变量看作是一个图中的点,对于每一个条件 \(x_{i}-x_{j}\le c_{k}\),从 \(j\) 向 \(i\) 连一条边权为 \(c_{k}\) 的有向边。

我们在求解的时候一般用 SPFA 来跑,虽然他最坏的时间复杂度是 \(O(nm)\) 的,但是我们的差分约束里面要是有负环的话,就说明是无解,再加上有负边权,SPFA 这个已死的算法成了最好的方法,更何况他在一些随机的图中跑的飞快。

最后一个问题,最后转化的式子是 \(x_{i}\le x_{j}+c_{k}\),为什么跑最短路?

但是我觉得,当你建图的时候使用的是 \(x_{i}-x_{j}\le c_{k}\) 形式的方程组建图时,即 \(j\) 向 \(i\) 连一条权值为 \(c_{k}\) 的边,应该选择跑最短路。

如果使用的是 \(x_{i}-s_{j}\ge c_{k}\) 形式的方程组来建图时,应该选择跑最长路。

P5960 【模板】差分约束算法

code:

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define N 50100
using namespace std;
int n,m,cnt,head[N];
queue<int>q;
struct SB{int w,v,next;}e[N<<1];
int dis[N],tot[N],vis[N];
inline void add(int u,int v,int w)
{
	e[++cnt].v=v;
	e[cnt].w=w;
	e[cnt].next=head[u];
	head[u]=cnt;
}
int SPFA()
{
	
	q.push(0);
	vis[0]=1;
	tot[0]++;
	while(!q.empty())
	{
		int u=q.front();
		q.pop();
		vis[u]=0;
		for(int i=head[u];i;i=e[i].next)
		{
			int v=e[i].v,w=e[i].w;
			if(dis[v]>dis[u]+w)
			{
				dis[v]=dis[u]+w;
				q.push(v);
				vis[v]=1;
				tot[v]++;
				if(tot[v]==n+1)
				return 0;
			}
		}
	}
	return 1;
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	  dis[i]=INF;
	for(int i=1;i<=n;i++)
	  add(0,i,0);
	for(int i=1;i<=m;i++)
	{
		int x,y,z;
		cin>>x>>y>>z;
		add(y,x,z);
	}
	if(!SPFA())
	  cout<<"NO"<<endl;
	else
	  for(int i=1;i<=n;i++)
		cout<<dis[i]<<" ";
	return 0;
}

标签:le,int,短路,笔记,约束,差分,dis
From: https://www.cnblogs.com/Multitree/p/16756214.html

相关文章

  • 时序约束(3)B站尤老师
    时序约束模型(1)让数据多延时一点 时序约束模型(2)让时钟多延时一点对于第一种时序约束模式,如果PLL采用的右移,那么需要采用multicycle约束 使用第二个上升沿进行时序分析对于DDR的时序分析边沿对齐模式,此种方式使得时钟延时尽量大 对于DDR的约束需要勾选AddDelay,否则......
  • Go笔记(十四):通道 channel
    1、通道通道channel是Go提供的一种用于各个协程(goroutine)之间的数据共享,保证数据同步交换的机制。协程是轻量级线程,类似于Java中的线程。2、通道的类型2.1、无缓冲通道用于同步通信,可保证在发送和接收数据时完成两个goroutine(协程)的数据交换。2.2、缓冲通道......
  • Go笔记(十五):并发编程
    一、协程的创建Go语言支持并发,只需要通过go关键字来开启goroutine(协程)即可。goroutine(协程)是轻量级线程,goroutine(协程)的调度是由Golang运行时进行管理的。goroutine语法格式(创建协程):go函数名(参数列表)示例代码如下:1packagemain2imp......
  • 5.5笔记
    1、格式化输入输出   CPU、内存、I/O设备在快速发展的过程中,有一个核心矛盾一直存在,就是三者之间的速度差异   平衡三者之间鸿沟的有效手段就是引入缓存   键盘---->stdin(内存,行缓冲区,标准输入缓冲区)---->程序---->stdout(内存,行缓冲区,标准输出缓冲区)---->屏幕 ......
  • Velocity----学习笔记
    Velocity判断空值方法:依据:$username与$!username的区别,当找不到username的时候,$username返回字符串"$username",而$!username返回空字符串""所以:#set($!username=='')可以判断字符串是否为空 以下为Velocity脚本摘要1、声明:#set($var=XXX)左边可以是以下的内容Variablereferen......
  • Go笔记(十三):包管理工具
    包管理工具,用来管理模块中包的依赖关系。下面来看看gomod的使用方法。1.1、初始化模块gomodinit项目模块名1.2、依赖关系处理,根据go.mod文件gomodtidy1.3、将依赖复制到项目下的vendor目录gomodvendor如果包被屏蔽(墙),随后使用gobuild-mod=vendo......
  • 【学习笔记】【题解】树形依赖 DP 选做
    地址:https://www.cnblogs.com/FReQuenter5156/p/shuxingyilaidp.html/简介这类背包本质上是分组背包问题。将一个节点的每一棵子树看作一组,进行分组背包。所谓分组背包,即在选择物品的时候,一开始将物品分为好几组,在选择时,可以从每一组中至多选择一件物品,问如何获得最大的价值,所......
  • Go笔记(十二):接口
    1、接口的声明Go语言中的接口是一种新的类型定义,拥有将具有共性的方法定义在一起的特性。任何其他类型只要实现了这些方法就是实现了这个接口。语法详情如下:/*定义接口*/typeinterface_nameinterface{method_name1[return_type]method_name2[return_type]......
  • Go笔记(十一):方法
    Go语言没有Java语言面向对象的特性,也无类对象的概念。但可以使用结构体实现这些特性。1、方法的声明Go中的方法是一种特殊的函数,与struct相关联,被称为struct的接收者。可以理解为方法就是有接收者的函数。语法格式如下:typemystructstruct{}func(recvmystruct)my......
  • CUDA入门笔记
    一个SM(StreamingMultiprocessor)中的所有SP(StreamingProcessor)是分成Warp的,共享同一个Memory和InstructionUnit(指令单元)。从硬件角度讲,一个GPU由多个SM组成(当然还有其他部分),一个SM包含有多个SP(以及还有寄存器资源,SharedMemory资源,L1cache,Scheduler,SPU,LD/ST单元等等)SM采......