初识差分约束
对于差分约束理解
差分约束解决了一类不等式组的解的问题,如
然后我们需要求的是的最大值
经过观察我们可以发现将得到
综上
如果我们用几何的方式来表示这三个不等式的话我们会有新的发现
不就是从到的最短距离吗
综上我们可以得出差分约束的一种解法-利用最短路算法
差分约束系统与最短路算法
现在我们将目光放在如何构造差分约束系统,并使用最短路算法解决。
对于任意不等式组
将其写成如下形式
并对每一个不等式建立有向边边权为
求的最大值 即求的最短路径
最大值与最小值的转换
当我们需要求的是的最小值的时候该怎么办
需要将差分约束系统所有不等式组变为
并对每一个不等式建立有向边边权为
求的最小值求的最长路径
这种方法和上述最短路法是等价的
最短路算法SPFA
由于差分约束系统用存在负权边,传统的最短贪心策略Dijkstra算法并不能处理负权边。
再者由于负权边会出现负权环,SPFA算法可以对负权图进行判断。
SPFA算法的原理:利用队列不断从队列中选取出结点出来松弛,直到队列为空为止。
基本模板
bool SPFA(int from,int to) {
memset(vis,0,sizeof(vis));
memset(cnt,0,sizeof(cnt));
for(int i=0;i<maxn;i++) dist[i] = inf;
vis[from] = true;
dist[from] = 0;
queue<int> qu;
qu.push(from);
cnt[from]=1;
while(!qu.empty()) {
int u = qu.front();qu.pop();
vis[u] = false;
for(int i=head[u];~i;i=edge[i].next) {
int v = edge[i].v;
if(dist[v] > dist[u] + edge[i].cost) {
dist[v] = dist[u] + edge[i].cost;
if(!vis[v]) {
vis[v] = true;
qu.push(v);
if(++cnt[v]>n) return false;
}
}
}
}
return true;
}
表示结点是否在队列中
记录了源点到其他点的最短路径
用于判断是否存在负权环,当一个结点进入队列超过次,即存在负权环
例题
例题1:ZOJ 2770
题意
给出个点表示个军营,表示第i个军营可容纳的士兵的最大值,接着给出条边表示从第到第个军营拥有的最少士兵数。求在满足以上条件下最少有多少士兵
题解
差分系统
设每个军营人数为,军营容量为,军营人数的前缀和为
-
写成前缀和的形式
-
从第个军营到第个军营的人数和至少为
转换为 -
每个军营都必须有人
转换为
目标:求解的最小值,设最小值为
转换于是我们只需要求解从点到点的最短路径
去负号即为注:存在负环则为不可估计无解
综上得到的差分约束系统为
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const int maxn = 1e3+10;
const int maxm = 1e5+10;
struct Edge {
int v;
ll cost;
int next;
Edge(){}
Edge(int _v,ll _c,int _n):v(_v),cost(_c),next(_n){}
};
Edge edge[maxm];
int n,m;
int head[maxn],tot;
bool vis[maxn]; // 是否在队列
int cnt[maxn]; // 每个点的入队次数
ll dist[maxn]; // 最短路径
ll cot[maxn];
inline void addedge(int u,int v,ll val) {
edge[tot] = Edge(v,val,head[u]);
head[u] = tot++;
}
bool SPFA(int from,int to) {
memset(vis,0,sizeof(vis));
memset(cnt,0,sizeof(cnt));
for(int i=0;i<maxn;i++) dist[i] = inf;
vis[from] = true;
dist[from] = 0;
queue<int> qu;
qu.push(from);
cnt[from]=1;
while(!qu.empty()) {
int u = qu.front();qu.pop();
vis[u] = false;
for(int i=head[u];~i;i=edge[i].next) {
int v = edge[i].v;
if(dist[v] > dist[u] + edge[i].cost) {
dist[v] = dist[u] + edge[i].cost;
if(!vis[v]) {
vis[v] = true;
qu.push(v);
if(++cnt[v]>n) return false;
}
}
}
}
return true;
}
inline void init() {
memset(head,-1,sizeof(head));tot = 0;
memset(cot,0,sizeof(cot));
}
int main()
{
while(~scanf("%d%d",&n,&m)) {
init();
ll cost;
for(int i=0;i<n;i++) {
scanf("%lld",&cost);
cot[i+1] = cot[i] + cost;
addedge(i,i+1,cost);
addedge(i+1,i,0);
}
for(int i=0,x,y;i<m;i++) {
scanf("%d%d%lld",&x,&y,&cost);
addedge(y,x-1,-cost);
//addedge(x-1,y,cot[y]-cot[x-1]);
}
bool flag = SPFA(n,0);
if(flag) printf("%lld\n",-dist[0]);
else printf("Bad Estimations\n");
}
return 0;
}