差分约束 + 01BFS
属于简单知识点的补档。
差分约束
差分约束系统 是一种特殊的
差分约束问题是最短路算法的一种巧妙应用。我们发现,差分约束系统中的每个约束条件
连边方法有两种:
- 连一条
的边权为 的边之后跑最短路,最终求出来的解是 时所有 的最大值; - 连一条
的边权为 的边之后跑最长路,最终求出来的解是 时所有 的最小值。
这两种方法不能混用。
注意这样连完边之后图不一定联通,此时我们只需定义一个 “超级源点”
至于题目中要求判断无解,我们只需用 SPFA 判断是否存在负环即可。若存在负环,则无解;否则,
例 1 P5960 【模板】差分约束
constexpr int MAXN=5005;
int n,m,head[MAXN],tot;
struct{
int v,to,w;
}e[MAXN<<1];
void addedge(int u,int v,int w){
e[++tot]={v,head[u],w};
head[u]=tot;
}
int dis[MAXN],cnt[MAXN];
bool vis[MAXN];
queue<int>q;
void spfa(){
memset(dis,0x3f,sizeof(int)*(n+5));
dis[0]=0;
vis[0]=1;
q.emplace(0);
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i;i=e[i].to)
if(dis[e[i].v]>dis[u]+e[i].w){
dis[e[i].v]=dis[u]+e[i].w;
if(!vis[e[i].v]){
vis[e[i].v]=1;
q.emplace(e[i].v);
if(++cnt[e[i].v]>n){
puts("NO");
exit(0);
}
}
}
}
}
int main(){
n=read(),m=read();
for(int i=1,u,v,w;i<=m;++i){
u=read(),v=read(),w=read();
addedge(v,u,w);
}
for(int i=1;i<=n;++i) addedge(0,i,0);
spfa();
for(int i=1;i<=n;++i) write(dis[i],' ');
return putchar('\n'),fw,0;
}
例 2 P1993 小 K 的农场
把所有不等式转化为标准形式即可。注意连边方法一定一定不能弄混。
#include<bits/stdc++.h>
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?EOF:*p1++)
using namespace std;
char buf[1<<20],*p1=buf,*p2=buf;
int read(){
int x=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x;
}
constexpr int MAXN=5005;
int n,m,head[MAXN],tot;
struct{
int v,to,w;
}e[MAXN<<1];
void addedge(int u,int v,int w){
e[++tot]={v,head[u],w};
head[u]=tot;
}
int dis[MAXN],cnt[MAXN];
bool vis[MAXN];
queue<int>q;
void spfa(){
memset(dis,0x3f,sizeof(int)*(n+5));
dis[0]=0;
vis[0]=1;
q.emplace(0);
while(!q.empty()){
int u=q.front();
q.pop();
vis[u]=0;
for(int i=head[u];i;i=e[i].to)
if(dis[e[i].v]>dis[u]+e[i].w){
dis[e[i].v]=dis[u]+e[i].w;
if(!vis[e[i].v]){
vis[e[i].v]=1;
q.emplace(e[i].v);
if(++cnt[e[i].v]>=n){
puts("No");
exit(0);
}
}
}
}
}
int main(){
n=read(),m=read();
for(int i=1,op,u,v;i<=m;++i){
op=read(),u=read(),v=read();
switch(op){
case 1: addedge(u,v,-read());break;
case 2: addedge(v,u,read());break;
case 3: addedge(u,v,0),addedge(v,u,0);break;
}
}
for(int i=1;i<=n;++i) addedge(0,i,0);
spfa();
return puts("Yes"),0;
}
01BFS
01BFS 用于解决边权只有
方法:用一个双端队列 deque,把边权为
01BFS 复杂度的正确性建立在类似 Dijkstra 的松弛的基础上,所以它不能求最长路。
例 [AGC056C] 01 Balanced
这道题的主要部分在这篇题解里。这里只放它的 01BFS 部分。
void bfs(){
memset(dis,-1,sizeof(int)*(n+5));
dis[0]=0;
deque<int>q;
q.emplace_back(0);
while(!q.empty()){
int u=q.front();
q.pop_front();
for(int i=head[u];i;i=e[i].to){
if(~dis[e[i].v]) continue;
dis[e[i].v]=dis[u]+e[i].w;
e[i].w?q.emplace_back(e[i].v):q.emplace_front(e[i].v);
}
}
}
即得易见平凡,仿照上例显然。留作习题答案略,读者自证不难。
反之亦然同理,推论自然成立。略去过程 ,由上可知证毕。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!