P5960 差分约束算法模板
差分约束
差分约束,一般用来解决有\(n\)个未知数,\(m\)个不等式方程的问题,形如:
\ x_{a_1}-x_{b_1}\leq y_1\\
\ x_{a_2}-x_{b_2}\leq y_2\\
\ \cdots\\
\ x_{a_m}-x_{b_m}\leq y_m\\
\end{cases}
\]
可以判断有没有解,以及给出一组解
简单观察可以知道,每个未知数的系数都为\(1\),且不等式一边是两个未知数相减,另一边是一个常数
为了达到这种形式,一般都需要将题目中的关系进行变形
模板题:P5960 【模板】差分约束算法
如何求解
考虑对于每个不等式\(x_i-x_j\leq y\),可以变形成\(x_i\leq x_j+y\)
这个式子,可以容易联想到最短路算法中的不等式\(dis(v)\leq dis(u)+w\),(容易吗?
那么,可以用最短路的方法来求解,从\(j\)向\(i\)联一条边权为\(y\)的边(\(i\)对应终点\(v\))
然后,就要新建一个虚拟节点\(n+1\),从它向每个节点连一个权值为\(0\)的边,\(dis(i)\leq dis(n+1)+0\)
求出的各项\(dis(i)\)其实就是对应的\(x_i\)
又由于\(dis(n+1)=0\),所以此时的\(dis(i)\)均小于\(0\),那么我们求出来的这组解,就是所有小于\(0\)的解里,最大的一组
那么如果产生了负环,就会出现\(x<x\)的情况,然后肯定无解,证明应该不难,但不想证了
因为在一个没有负环的图上,最短路肯定不会经过多于\(n\)个点,也不会经过多于\(n-1\)条边
所以,我们用 spfa 来求解这个最短路问题,如果某个节点入队\(n\)次,就说明存在负环
还有一种,就是记录\(cnt_i\)为\(1\rightarrow i\)的最短路上的点的个数,如果\(cnt_i>n\)就说明存在负环
这种方法倒是更直观,据说跑起来也更快
当然,\(cnt_1=1,cnt_v=cnt_u+1\)
但是代码里放的是第一种
没错,spfa 肯定没死,他是唯一能处理负环的算法(起码我没听说过其它的
最短路
所以可以写出用最短路实现的代码:
#include<cstdio>
#include<queue>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
int x=0,y=1;
char c=std::getchar();
while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
return y?x:-x;
}
int n,m;
int fir[5006],nex[10006],to[10006],w[10006],tot;
int cnt[5005],in[5005];
int dis[5005];
std::queue<int>q;
inline void add(int a,int b,int c){
to[++tot]=b;w[tot]=c;
nex[tot]=fir[a];fir[a]=tot;
}
inline int spfa(){
q.push(n+1);
std::memset(dis,0x3f,sizeof dis);
dis[n+1]=0;in[n+1]=1;
while(!q.empty()){
reg int u=q.front();q.pop();in[u]=0;
for(reg int v,i=fir[u];i;i=nex[i]){
v=to[i];
if(dis[v]>dis[u]+w[i]){
dis[v]=dis[u]+w[i];
if(!in[v]){
if(++cnt[v]==n) return 0;
in[v]=1;q.push(v);
}
}
}
}
return std::rand();
}
int main(){
n=read();m=read();
for(reg int i=1;i<=n;i++) add(n+1,i,0);
for(reg int a,b,c,i=1;i<=m;i++){
a=read();b=read();c=read();
add(b,a,c);
}
if(!spfa()) std::puts("NO");
else for(reg int i=1;i<=n;i++) std::printf("%d\n",dis[i]);
return 0;
}
最长路
其实不等式\(x_i-x_j\leq y\)还可以变形成\(x_j\geq x_i-y\)
所以就应该从\(i\)向\(j\)连一个权值为\(-y\)的边,然后跑最长路,判断正环
当然,虚拟节点也要建,从\(n+1\)连向\(i\),代表\(dis(i)\geq dis(n+1),dis(n+1)=0\)
因此,这种方法求出的是,当\(x_i\geq 0\),的最小解
所以代码是这样的:
#include<cstdio>
#include<queue>
#include<algorithm>
#include<iostream>
#include<cmath>
#include<iomanip>
#include<cstring>
#define reg register
#define EN std::puts("")
#define LL long long
inline int read(){
int x=0,y=1;
char c=std::getchar();
while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
return y?x:-x;
}
int n,m;
int fir[5006],nex[10006],to[10006],w[10006],tot;
int cnt[5005],in[5005];
int dis[5005];
std::queue<int>q;
inline void add(int a,int b,int c){
to[++tot]=b;w[tot]=c;
nex[tot]=fir[a];fir[a]=tot;
}
inline int spfa(){
q.push(n+1);
for(reg int i=1;i<=n;i++) dis[i]=-5e8;
in[n+1]=1;
while(!q.empty()){
reg int u=q.front();q.pop();in[u]=0;
for(reg int v,i=fir[u];i;i=nex[i]){
v=to[i];
if(dis[v]<dis[u]+w[i]){
dis[v]=dis[u]+w[i];
if(!in[v]){
if(++cnt[v]==n) return 0;
in[v]=1;q.push(v);
}
}
}
}
return std::rand();
}
int main(){
n=read();m=read();
for(reg int i=1;i<=n;i++) add(n+1,i,0);
for(reg int a,b,c,i=1;i<=m;i++){
a=read();b=read();c=read();
add(a,b,-c);
}
if(!spfa()) std::puts("NO");
else for(reg int i=1;i<=n;i++) std::printf("%d\n",dis[i]);
return 0;
}
一些题目
在处理差分约束题目时,主要就是要把关系进行变形
看清楚边是\(i\rightarrow j\)还是\(j\rightarrow i\),边权是\(y\)还是\(-y\)
如果出现未知数系数不为\(1\)的情况,一般使用乘积最短路的形式,但这时候就要求没有常数,也就是\(x_i\leq kx_j\)
P1993 小K的农场,题解,比较经典的一题
P4926 [1007]倍杀测量者,这个就是刚才说的乘积最短路,但是具体的实现是要取\(\log\),然后变成加法的,洛谷上有一个名为“最短路”的题就是这个
SCOI2011 糖果
虫洞,uva上的一题
P5960 差分约束算法模板的更多相关文章
- 差分约束算法————洛谷P4878 [USACO05DEC] 布局
题目: 不难看出题意主要是给出ml+md个格式为xi-xj<=ak的不等式,xi-xj为i,j俩头牛的距离,要我们求x1-xn的最大值. 经过上下加减我们可以将这几个不等式化成x1-xn< ...
- 鉴于spfa基础上的差分约束算法
怎么搞? 1. 如果要求最大值 想办法把每个不等式变为标准x-y<=k的形式,然后建立一条从y到x权值为k的边,变得时候注意x-y<k =>x-y<=k ...
- P5960 【模板】差分约束算法
题目描述 给出一组包含 $m$ 个不等式,有 $n$ 个未知数的形如: 的不等式组,求任意一组满足这个不等式组的解. 输入格式 第一行为两个正整数 $n,m$,代表未知数的数量和不等式的数量. 接下来 ...
- P1993 小K的农场(差分约束)
小K的农场 题目描述 小K在MC里面建立很多很多的农场,总共n个,以至于他自己都忘记了每个农场中种植作物的具体数量了,他只记得一些含糊的信息(共m个),以下列三种形式描述: 农场a比农场b至少多种植了 ...
- 差分约束+spfa【模板】
相比dij,spfa优点是可处理含负边不含负圈的最短路问题,缺点是算法复杂度不太好[貌似可以使用两种优化.LLL和SLF] 差分约束就是将一些不等式转化为图中的带权边,然后求解最短路或最长路的方法 洛 ...
- bzoj 2330 [SCOI2011]糖果 差分约束模板
题目大意 幼儿园里有N个小朋友,lxhgww老师现在想要给这些小朋友们分配糖果,要求每个小朋友都要分到糖果.但是小朋友们也有嫉妒心,总是会提出一些要求,比如小明不希望小红分到的糖果比他的多,于是在分配 ...
- 算法复习——差分约束(ssoi种树)
题目: 题目描述 为了绿化乡村,H 村积极响应号召,开始种树了. H 村里有 n 幢房屋,这些屋子的排列顺序很有特点,在一条直线上.于是方便起见,我们给它们标上 1-n .树就种在房子前面的空地上. ...
- POJ-3159(差分约束+Dijikstra算法+Vector优化+向前星优化+java快速输入输出)
Candies POJ-3159 这里是图论的一个应用,也就是差分约束.通过差分约束变换出一个图,再使用Dijikstra算法的链表优化形式而不是vector形式(否则超时). #include< ...
- POJ 3159 Candies(差分约束,最短路)
Candies Time Limit: 1500MS Memory Limit: 131072K Total Submissions: 20067 Accepted: 5293 Descrip ...
随机推荐
- NullPointerException的处理新方式,Java14真的太香了
在Java语言中,处理空指针往往是一件很头疼的事情,一不小心,说不定就搞出个线上Bug,让你的绩效考核拿到3.25.最近新出的Java14,相信大家都有所耳闻,那么今天就来看看,面对NullPoint ...
- 基于 HTML5 WebGL 的楼宇智能化集成系统(三)
前言 2018年7月,信息化部印发了<工业互联网平台建设及推广指南>和<工业互联网平台评价方法>,掀起了 工业互联网 的浪潮,并成为热词写入了报告中.同为信息发展下 ...
- Pytest系列(18)- 超美测试报告插件之allure-pytest的基础使用
如果你还想从头学起Pytest,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1690628.html 官方介绍 Allure Frame ...
- Netty是如何处理新连接接入事件的?
更多技术分享可关注我 前言 前面的分析从Netty服务端启动过程入手,一路走到了Netty的心脏——NioEventLoop,又总结了Netty的异步API和设计原理,现在回到Netty服务端本身,看 ...
- Python实战---制作专属有声小说(调用百度语音合成接口)
这一次的目标是使用百度云的人工智能接口,实现文字转语音的实时转换,将小说文字转换成语音朗读出来. 百度云接口调用 百度的这个接口对于我们普通用户非常友好,他的很多功能都是免费的,而且我们每天可以免费调 ...
- 如何初学python?资深程序员浅谈,教你学会入门python
我认为python应该是现在市面上最简单,也是最值钱的一门编程语言,所以学习的人是越来越多,但是,如何初学python?这个问题困扰着很多初学python的人,今天,给大家简单聊聊这个话题. 我曾经也 ...
- 食物链 POJ - 1182 (并查集的两种写法)
这是一个非常经典的带权并查集,有两种写法. 1 边权并查集 规定一下,当x和y这条边的权值为0时,表示x和y是同类,当为1时,表示x吃y,当为2时,表示x被y吃. 一共有三种状态,如图,当A吃B,B吃 ...
- 基于 HTML5 WebGL 的高炉炼铁厂可视化系统
前言 在当今 工业4.0 新时代的推动下,不仅迎来了 工业互联网 的发展,还开启了 5G 时代的新次元.而伴随着带宽的提升,网络信息飞速发展,能源管控上与实时预警在工业互联网中也占着举足轻 ...
- Spring Boot 中使用自定义注解,AOP 切面打印出入参日志及Dubbo链路追踪透传traceId
一.使用背景 开发排查系统问题用得最多的手段就是查看系统日志,在分布式环境中一般使用 ELK 来统一收集日志,但是在并发大时使用日志定位问题还是比较麻烦,由于大量的其他用户/其他线程的日志也一起输出穿 ...
- [PHP] excel 的导入导出
其实excel导入导出挺简单的,导出最简单! 其原理都是把数据读出来,导出是从数据库中读出数据,导入是从文件读出数据! 导出写入文件,导入写入数据库! 但是在导入表的时候,用的是PHPExcel, 不 ...