(有任何问题欢迎留言或私聊 && 欢迎交流讨论哦
目录
题意:传送门
原题目描述在最下面。
给定一组约束条件
(
u
,
v
,
w
)
(u,v,w)
(u,v,w),表示
d
i
s
[
v
]
−
d
i
s
[
u
]
<
=
w
dis[v]-dis[u]<=w
dis[v]−dis[u]<=w。问
d
i
s
[
n
]
−
d
i
s
[
1
]
dis[n]-dis[1]
dis[n]−dis[1]最大为多少。
差分约束:
-
求最大差值转化为最短路问题,约束条件为 d i s [ v ] − d i s [ u ] < = w dis[v]-dis[u]<=w dis[v]−dis[u]<=w转化为最短路问题。
-
求最小差值转化为最长路问题,约束条件为 d i s [ v ] − d i s [ u ] > = w dis[v]-dis[u]>=w dis[v]−dis[u]>=w转化为最长路问题。
-
最长路问题的解法:边权设为负值,跑最短路,答案取相反数。
栗子
此题过于简单,不做栗子,在此以poj1201作为栗子:
- 有一个序列,题目用n个整数组合 ( a i , b i , c i ) (ai,bi,ci) (ai,bi,ci)来描述它, ( a i , b i , c i ) (ai,bi,ci) (ai,bi,ci)表示在该序列中处于 ( a i , b i ) (ai,bi) (ai,bi)这个区间的整数至少有 c i ci ci个。如果存在这样的序列,请求出满足题目要求的最短的序列长度是多少。
求最短序列长度,不就是求最小差值问题吗?那就是要求最长路了。
考虑约束条件:
d
i
s
[
u
]
dis[u]
dis[u]表示从
1
−
u
1-u
1−u的整数个数。
d
i
s
[
v
]
−
d
i
s
[
u
]
>
=
w
i
dis[v]-dis[u]>=wi
dis[v]−dis[u]>=wi 还有
d
i
s
[
u
]
−
d
i
s
[
u
−
1
]
>
=
0
dis[u]-dis[u-1]>=0
dis[u]−dis[u−1]>=0,
d
i
s
[
u
−
1
]
−
d
i
s
[
u
]
>
=
−
1
dis[u-1]-dis[u]>=-1
dis[u−1]−dis[u]>=−1
跑spfa注意:
(下面两种方法我还没写,先口胡一波)
方法一:
把边权设为负值,跑普通最短路,
m
e
m
s
e
t
(
d
i
s
,
I
N
F
)
,
d
i
s
[
s
t
a
r
t
]
=
0
memset(dis, INF), dis[start]=0
memset(dis,INF),dis[start]=0,然后答案取反。
方法二:
m
e
m
s
e
t
(
d
i
s
,
−
I
N
F
)
,
d
i
s
[
s
t
]
=
0
memset(dis,-INF),dis[st]=0
memset(dis,−INF),dis[st]=0,判断条件改为
i
f
(
d
i
s
[
v
]
<
d
i
s
[
u
]
+
w
i
)
if(dis[v]<dis[u]+w_{i})
if(dis[v]<dis[u]+wi)
思路:
本题
d
i
s
[
v
]
−
d
i
s
[
u
]
<
=
w
dis[v]-dis[u]<=w
dis[v]−dis[u]<=w,连一条
u
−
>
v
,
权
值
为
w
u->v,权值为w
u−>v,权值为w的边,跑最短路。
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e5+5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
int n,m;
struct lp{
int u,v,w,nex;
}cw[N*2];
struct lh{
int u,w;
lh(){}
lh(int a,int b){u=a,w=b;}
bool operator <(const lh &a)const{
return w>a.w;
}
};
int head[N],tot,vis[N],dis[N];
void dij(){
for(int i=1;i<=n;++i)dis[i]=INF,vis[i]=0;
dis[1]=0;
priority_queue<lh>Q;
Q.push(lh(1,0));
while(!Q.empty()){
lh b = Q.top();Q.pop();
int u = b.u;
if(vis[u])continue;
vis[u]=1;
if(dis[u]<b.w)continue;
for(int i=head[u];~i;i=cw[i].nex){
int v = cw[i].v;
if(dis[v]>dis[u]+cw[i].w){
dis[v]=dis[u]+cw[i].w;
if(vis[v])continue;
Q.push(lh(v,dis[v]));
}
}
}
printf("%d\n", dis[n]);
}
inline void add(int u,int v,int w){
cw[++tot].u=u;cw[tot].v=v;cw[tot].w=w;cw[tot].nex=head[u];
head[u]=tot;
}
inline void init(){
memset(head,-1,sizeof(head));
tot=-1;
}
int main(){
while(~scanf("%d%d",&n,&m)){
init();
while(m--){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
dij();
}
return 0;
}
原题目描述:
Description
During the kindergarten days, flymouse was the monitor of his class. Occasionally the head-teacher brought the kids of flymouse’s class a large bag of candies and had flymouse distribute them. All the kids loved candies very much and often compared the numbers of candies they got with others. A kid A could had the idea that though it might be the case that another kid B was better than him in some aspect and therefore had a reason for deserving more candies than he did, he should never get a certain number of candies fewer than B did no matter how many candies he actually got, otherwise he would feel dissatisfied and go to the head-teacher to complain about flymouse’s biased distribution.
snoopy shared class with flymouse at that time. flymouse always compared the number of his candies with that of snoopy’s. He wanted to make the difference between the numbers as large as possible while keeping every kid satisfied. Now he had just got another bag of candies from the head-teacher, what was the largest difference he could make out of it?
Input
The input contains a single test cases. The test cases starts with a line with two integers N and M not exceeding 30 000 and 150 000 respectively. N is the number of kids in the class and the kids were numbered 1 through N. snoopy and flymouse were always numbered 1 and N. Then follow M lines each holding three integers A, B and c in order, meaning that kid A believed that kid B should never get over c candies more than he did.
Output
Output one line with only the largest difference desired. The difference is guaranteed to be finite.
Sample Input
2 2
1 2 5
2 1 4
Sample Output
5
Hint
32-bit signed integer type is capable of doing all arithmetic.
Source
POJ Monthly–2006.12.31, Sempr
推荐博客
1 2
对一组约束系统:
x1-x2≤0
x1-x5≤-1
x2-x5≤1
x3-x1≤5
x4-x1≤4
x4-x3≤-1
x5-x3≤-3
x5-x4≤-3
该问题的一个解为x=(-5,-3,0,-1,-4),另一个解y=(0,2,5,4,1),这2个解是有联系的:y中的每个元素比x中相应的元素大5。
- 引理:设x=(x1,x2,…,xn)是差分约束系统Ax≤b的一个解,d为任意常数。则x+d=(x1+d,x2+d,…,xn+d)也是该系统Ax≤b的一个解。
约束图
在一个差分约束系统Ax≤b中,m X n的线性规划矩阵A可被看做是n顶点,m条边的图的关联矩阵。对于i=1,2,…,n,图中的每一个顶点vi对应着n个未知量的一个xi。图中的每个有向边对应着关于两个未知量的m个不等式中的一个。
给定一个差分约束系统Ax≤b,相应的约束图是一个带权有向图G=(V,E),其中V={v0,v1,…,vn},而且E={ (vi,vj) : xj-xi≤bk是一个约束}∪{ (v0,v1) , (v0,v2) , … , (v0,vn) }。引入附加顶点v0是为了保证其他每个顶点均从v0可达。因此,顶点集合V由对应于每个未知量xi的顶点vi和附加的顶点v0组成。边的集合E由对应于每个差分约束条件的边与对应于每个未知量xi的边(v0,vi)构成。如果xj-xi≤bk是一个差分约束,则边(vi,vj)的权w(vi,vj)=bk(注意i和j不能颠倒),从v0出发的每条边的权值均为0。
定理:给定一差分约束系统Ax≤b,设G=(V,E)为其相应的约束图。如果G不包含负权回路,那么x=( d(v0,v1) , d(v0,v2) , … , d(v0,vn) )是此系统的一可行解,其中d(v0,vi)是约束图中v0到vi的最短路径(i=1,2,…,n)。如果G包含负权回路,那么此系统不存在可行解。
差分约束问题的求解
n个未知量m个约束条件的一个差分约束系统产生出一个具有n+1个顶点和n+m条边的约束图。采用Bellman-Ford或SPFA。
也可以一开始把所有点加入队列然后初始化
d
i
s
[
i
]
=
0
,
v
i
s
[
i
]
=
1
dis[i]=0,vis[i]=1
dis[i]=0,vis[i]=1。
poj1201最长路
int n, m;
struct lp{
int v, nex;
LL w;
}cw[MXN*10];
int head[MXN], tot;
void add_edge(int u,int v,int c) {
cw[++tot].v = v;cw[tot].w = c; cw[tot].nex=head[u];
head[u] = tot;
}
LL dis[MXN];
int vis[MXN], tim[MXN];
void spfa(int s,int t) {
for(int i = 0; i <= 50000; ++i) dis[i] = INF, vis[i] = 0, tim[i] = 0;
dis[s] = 0;
queue<int> Q;
Q.push(s);
tim[s] = 1;
while(!Q.empty()) {
int u = Q.front(); Q.pop();
vis[u] = 0;
for(int i = head[u]; ~i; i = cw[i].nex) {
int v = cw[i].v;
if(dis[v] > dis[u] + cw[i].w) {
dis[v] = dis[u] + cw[i].w;
if(tim[v] > n) return;
if(vis[v]) continue;
vis[v] = 1;
tim[v] ++;
Q.push(v);
}
}
}
}
int main() {
while(~scanf("%d", &n)){
int m1 = INF, m2 = 0;
memset(head,-1,sizeof(head));
tot = -1;
for(int i = 0, a, b, c; i < n; ++i) {
scanf("%d%d%d", &a, &b, &c);
++ b;
add_edge(a, b, -c);
m1 = min(a, m1);
m2 = max(b, m2);
}
//dis[i+1] - dis[i] <= 1
//dis[b] - dis[a] >= c
for(int i = m1; i < m2; ++i) {
add_edge(i+1, i, 1);
add_edge(i, i+1, 0);
}
spfa(m1, m2);
printf("%lld\n", -dis[m2]);
}
return 0;
}
int n, m;
struct lp{
int v, nex;
LL w;
}cw[MXN*10];
int head[MXN], tot;
void add_edge(int u,int v,int c) {
cw[++tot].v = v;cw[tot].w = c; cw[tot].nex=head[u];
head[u] = tot;
}
LL dis[MXN];
int vis[MXN], tim[MXN];
void spfa(int s,int t) {
for(int i = 0; i <= 50000; ++i) dis[i] = -INF, vis[i] = 0, tim[i] = 0;
dis[s] = 0;
queue<int> Q;
Q.push(s);
tim[s] = 1;
while(!Q.empty()) {
int u = Q.front(); Q.pop();
vis[u] = 0;
for(int i = head[u]; ~i; i = cw[i].nex) {
int v = cw[i].v;
if(dis[v] < dis[u] + cw[i].w) {
dis[v] = dis[u] + cw[i].w;
if(tim[v] > n) return;
if(vis[v]) continue;
vis[v] = 1;
tim[v] ++;
Q.push(v);
}
}
}
}
int main() {
while(~scanf("%d", &n)){
int m1 = INF, m2 = 0;
memset(head,-1,sizeof(head));
tot = -1;
for(int i = 0, a, b, c; i < n; ++i) {
scanf("%d%d%d", &a, &b, &c);
++ b;
add_edge(a, b, c);
m1 = min(a, m1);
m2 = max(b, m2);
}
//dis[i+1] - dis[i] <= 1
//dis[b] - dis[a] >= c
for(int i = m1; i < m2; ++i) {
add_edge(i+1, i, -1);
add_edge(i, i+1, 0);
}
spfa(m1, m2);
printf("%lld\n", dis[m2]);
}
return 0;
}