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

【学习笔记】差分约束系统

时间:2022-09-19 14:57:05浏览次数:87  
标签:ch int 笔记 约束 vis 差分 x2 include dis

【图论】差分约束系统

前置芝士

SPFA判负环与最短路

SPFA判负环

负环定义:边の权值之和为负数的环

不会真的有人不会SPFA吧

先放张图

就是在SPFA跑最短路的时候判断一下有没有一个点被访问的次数大于n,因为对于任意一个1能够到达的却不存在负环的路径,这条路径上每个节点被访问的次数一定是1~n,否则其中一定会有负环存在(可以自己举例验证一下)

板子题 AC代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<algorithm>
#define int long long

using namespace std;

const int maxn=3e3+5;

inline int read()
{
	int w=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch=='-')
		{
			f=-1;
		}
		ch=getchar();
	}
	while(ch>='0' && ch<='9')
	{
		w=(w<<3)+(w<<1)+(ch^48);
		ch=getchar();
	}
	return w*f;
}

int n,m,t;

int tot;

int cnt[maxn];

int dis[maxn];

bool vis[maxn];

int head[maxn];

struct edge
{
	int to;
	int val;
	int from;
	int next;
}e[2*maxn];

void add(int x,int y,int z)
{
	tot++;
	e[tot].to=y;
	e[tot].from=x;
	e[tot].val=z;
	e[tot].next=head[x];
	head[x]=tot;
}

bool spfa()
{
	queue <int> q;
	
	q.push(1);
	dis[1]=0;
	vis[1]=true;
	cnt[1]=1;
	
	while(!q.empty())
	{
		int k=q.front();
		
		q.pop();
		
		vis[k]=false;
		
		for(int i=head[k];i;i=e[i].next)
		{
			int to=e[i].to;
			
			if(dis[to]>dis[k]+e[i].val)
			{
				dis[to]=dis[k]+e[i].val;
				if(vis[to]==false)
				{
					vis[to]=true;
					q.push(to);
					cnt[to]++;
					if(cnt[to]>n)
					{
						return true;
					}
				}
			}
		}
	}
	
	return false;
}

signed main()
{
	t=read();
	
	while(t--)
	{
		tot=0;
		memset(dis,0x3f3f3f,sizeof(dis));
		memset(cnt,0,sizeof(cnt));
		memset(vis,false,sizeof(vis));
		memset(e,0,sizeof(e));
		memset(head,0,sizeof(head));
		
		n=read();
		m=read();
	
		for(int i=1;i<=m;i++)
		{
			int a=read();
			int b=read();
			int c=read();
			add(a,b,c);
			if(c>=0)
			{
				add(b,a,c);
			}
		}
	
		if(spfa())
		{
			cout<<"YES"<<endl;
		}
		else
		{
			cout<<"NO"<<endl;
		}	
	}
	
	return 0;
}

差分约束系统

给出一组包含 \(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} \]

的不等式组,求任意一组满足这个不等式组的解。

思考转化为图论

对于每个形如\(x1-x2\leq y\)的不等式,都可以转化为\(x1\leq x2+y\)

看着这个式子就很眼熟的样子

if(dis[to]>dis[k]+e[i].val)
{
    dis[to]=dis[k]+e[i].val;
}

这不就是单源最短路径??

所以对于每个式子\(x1-x2\leq y\),都可以看做x2到x1有一条权值为y的连边,那么每个x对于源点0的最短路径长度dis[x]一定是满足不等式的一组解,而当有负环存在时,一定无解

其实还是SPFA跑0到各个点的单源最短路径在加上判负环啦,就是个SPFA的板子

板子代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<algorithm>

using namespace std;

const int maxn=5e3+5;

inline int read()
{
	int w=0,f=1;
	char ch=getchar();
	while(ch<'0' || ch>'9')
	{
		if(ch=='-')
		{
			f=-1;
		}
		ch=getchar();
	}
	while(ch>='0' && ch<='9')
	{
		w=(w<<3)+(w<<1)+(ch^48);
		ch=getchar();
	}
	return w*f;
}

int tot;

int n,m;

int dis[maxn];

int head[maxn];

bool vis[maxn];

int cnt[maxn];

struct edge
{
	int from;
	int to;
	int val;
	int next;
}e[maxn*2];

void add(int x,int y,int z)
{
	tot++;
	e[tot].to=y;
	e[tot].from=x;
	e[tot].val=z;
	e[tot].next=head[x];
	head[x]=tot;
}

bool spfa()
{
	queue <int> q;
	
	memset(dis,0x3f3f3f,sizeof(dis));
	memset(vis,false,sizeof(vis));
	
	q.push(0);
	dis[0]=0;
	cnt[0]=1;
	vis[0]=true;
	
	while(!q.empty())
	{
		int k=q.front();
		
		q.pop();
		
		vis[k]=false;
		
		for(int i=head[k];i;i=e[i].next)
		{
			int to=e[i].to;
			
			if(dis[to]>dis[k]+e[i].val)
			{
				dis[to]=dis[k]+e[i].val;
			
				if(vis[to]==false)
				{
					vis[to]=true;
					cnt[to]++;
					q.push(to);
					if(cnt[to]>n+1)
					{
						return true;
					}
				}
			}
		}
	}
	
	return false;
}

int main()
{
	n=read();
	m=read();
	
	for(int i=1;i<=m;i++)
	{
		int u,v,w;
		u=read();
		v=read();
		w=read();
		add(v,u,w);
	}
	
	for(int i=1;i<=n;i++)
	{
		add(0,i,0);//要记得把0和个点加进去,不然0就是一个单独的节点了
	}
	
	if(!spfa())
	{
		for(int i=1;i<=n;i++)
		{
			cout<<dis[i]<<" ";
		}
	}
	else
	{
		cout<<"NO"<<endl;
	}
	
	return 0;
}

补充&总结

对于一些题目,其约束条件可能会形如\(x1-x2\geq y\),我们的解决方案通常是两边同时乘上-1,得到\(x2-x1\leq -y\),然后就和上面一样力,而当出现x1-x2=y时,我们可以拆分将其为\(x1-x2\leq y\)和\(x1-x2\geq y\)两个约束条件进行维护即可

To 初赛失利のOIer

尘埃纵然很轻,但是尘埃永远领略不到云彩有多轻。因为云彩在尘埃遥不可及的平流层之上,俯瞰着一切,而尘埃也至多只能看见云彩投在地下的一段阴影。

但是呢,话也不能这么说。云彩随着大气环流不断更新,这一朵可能再不会与我这种尘埃相遇。所谓的阴影也只是一瞬罢了。

尘埃…也应该在地壳表面拥有自己的精彩啊。

标签:ch,int,笔记,约束,vis,差分,x2,include,dis
From: https://www.cnblogs.com/SitoASK/p/16707656.html

相关文章

  • 《软件测试的艺术》读书笔记(三)
    3.3用于代码检查的错误列表常见错误对照表,容易出现的问题:过于注重代风格码而不是代码错误、过于模糊不够具体。           3.3.1数据引用错误......
  • 【白话设计模式】课程笔记整理
    白话设计模式六大设计原则开闭原则Open-ClosePrinciple,OCP在⾯向对象编程领域中,开闭原则规定软件中的对象、类、模块和函数对扩展应该是开放的,但对于修改是封闭的。......
  • 道长的算法笔记:贪心算法经典模型
    (一)区间模型(1.1)区间合并(1.2)区间选点(1.3)区间覆盖(1.4)区间分组(二)贪心常用证明方法......
  • rabbit-mq集群docker搭建笔记
    1.安装docker1、yum包更新到最新yumupdate2、安装需要的软件包,yum-util提供yum-config-manager功能,另外两个是devicemapper驱动依赖的yuminstall-yyum-uti......
  • redis学习笔记
    Redis一、rhel7安装redis6.0.6[[email protected]]#cat/etc/redhat-releaseRedHatEnterpriseLinuxServerrelease7.6(Maipo)1、下载安装包地址:https:......
  • 《js 设计模式与开发实践》读书笔记 13
     职责链模式的定义是:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。 ......
  • 《js 设计模式与开发实践》读书笔记 14(完)
    在传统面向对象语言中,给对象添加功能常常使用继承的方式,但是继承的方式并不灵活,还会带来许多问题:一方面会导致超类和子类之间存在强耦合性,当超类改变时,子类也会随之改变;另......
  • Android最强布局——ConstraintLayout约束布局
    ConstraintLayout首先,现附上官方文档:ConstraintLayout官方文档约束布局ConstraintLayout是一个ViewGroup,可以在Api9以上的Android系统使用它,它的出现主要是为了解决布局......
  • 【RocketMQ 课程笔记】7.RocketMQ高可用方案
    RocketMQ高可用消息生产消费流程​ Broker即MQ服务器;​ NameServer可理解为注册中心。Broker主挂了的情况Broker主从都挂了的情况Broker双主挂了的情......
  • 【RocketMQ 课程笔记】11.RocketMQ消息发送之普通消息
    RocketMQ消息发送之普通消息架构拓扑NameServer:192.168.31.103Master:192.168.31.105Slave:192.168.31.111执行流程Master与Slave启动向NameServer注册生产者Prod......