UVa 515 - King (差分约束系统 + SPFA求带负权最短路)

下面是差分约束系统的详细介绍,以及解决方法~ 摘抄自 xuezhongfenfei(他好像也是转的....)

差分约束系统

X1 - X2 <= 0

X1 - X5 <= -1

X2 - X5 <= 1

X3 - X1 <= 5

X4 - X1 <= 4

X4 - X3 <= -1

X5 - X3 <= -3

X5 - X4 <= -3

不等式组(1)

全都是两个未知数的差小于等于某个常数(大于等于也可以,因为左右乘以-1就可以化成小于等于)。这样的不等式组就称作差分约束系统。

这个不等式组要么无解,要么就有无数组解。因为如果有一组解{X1, X2, ..., Xn}的话,那么对于任何一个常数k,{X1 + k, X2 + k, ..., Xn + k}肯定也是一组解,因为任何两个数同时加一个数之后,它们的差是不变的,那么这个差分约束系统中的所有不等式都不会被破坏。

差分约束系统的解法利用到了单源最短路径问题中的三角形不等式。即对于任何一条边u -> v,都有:

d(v) <= d(u) + w(u, v)

其中d(u)和d(v)是从源点分别到点u和点v的最短路径的权值,w(u, v)是边u -> v的权值。 显然以上不等式就是d(v) - d(u) <= w(u, v)。这个形式正好和差分约束系统中的不等式形式相同。于是我们就可以把一个差分约束系统转化成一张图,每个未知数Xi对应图中的一个顶点Vi,把所有不等式都化成图中的一条边。对于不等式Xi
- Xj <= c,把它化成三角形不等式:Xi <= Xj + c,就可以化成边Vj -> Vi,权值为c。最后,我们在这张图上求一次单源最短路径,这些三角形不等式就会全部都满足了,因为它是最短路径问题的基本性质嘛。

话说回来,所谓单源最短路径,当然要有一个源点,然后再求这个源点到其他所有点的最短路径。那么源点在哪呢?我们不妨自已造一个。以上面的不等式组为例,我们就再新加一个未知数X0。然后对原来的每个未知数都对X0随便加一个不等式(这个不等式当然也要和其它不等式形式相同,即两个未知数的差小于等于某个常数)。我们索性就全都写成Xn - X0 <= 0,于是这个差分约束系统中就多出了下列不等式:

X1 - X0 <= 0

X2 - X0 <= 0

X3 - X0 <= 0

X4 - X0 <= 0

X5 - X0 <= 0

不等式组(2)

对于这5个不等式,也在图中建出相应的边。最后形成的图如下:

图1 

图中的每一条边都代表差分约束系统中的一个不等式。现在以V0为源点,求单源最短路径。最终得到的V0到Vn的最短路径长度就是Xn的一个解啦。从图1中可以看到,这组解是{-5, -3, 0, -1, -4}。当然把每个数都加上10也是一组解:{5, 7, 10, 9, 6}。但是这组解只满足不等式组(1),也就是原先的差分约束系统;而不满足不等式组(2),也就是我们后来加上去的那些不等式。当然这是无关紧要的,因为X0本来就是个局外人,是我们后来加上去的,满不满足与X0有关的不等式我们并不在乎。

也有可能出现无解的情况,也就是从源点到某一个顶点不存在最短路径。也说是图中存在负权的圈。这一点我就不展开了,请自已参看最短路径问题的一些基本定理。

其实,对于图1来说,它代表的一组解其实是{0, -5, -3, 0, -1, -4},也就是说X0的值也在这组解当中。但是X0的值是无可争议的,既然是以它作为源点求的最短路径,那么源点到它的最短路径长度当然是0了。因此,实际上我们解的这个差分约束系统无形中又存在一个条件:

X0 = 0

也就是说在不等式组(1)、(2)组成的差分约束系统的前提下,再把其中的一个未知数的值定死。这样的情况在实际问题中是很常见的。比如一个问题表面上给出了一些不等式,但还隐藏着一些不等式,比如所有未知数都大于等于0或者都不能超过某个上限之类的。比如上面的不等式组(2)就规定了所有未知数都小于等于0。

对于这种有一个未知数定死的差分约束系统,还有一个有趣的性质,那就是通过最短路径算法求出来的一组解当中,所有未知数都达到最大值。下面我来粗略地证明一下,这个证明过程要结合Bellman-Ford算法的过程来说明。

假设X0是定死的;X1到Xn在满足所有约束的情况下可以取到的最大值分别为M1、M2、……、Mn(当然我们不知道它们的值是多少);解出的源点到每个点的最短路径长度为D1、D2、……、Dn。

基本的Bellman-Ford算法是一开始初始化D1到Dn都是无穷大。然后检查所有的边对应的三角形不等式,一但发现有不满足三角形不等式的情况,则更新对应的D值。最后求出来的D1到Dn就是源点到每个点的最短路径长度。

如果我们一开始初始化D1、D2、……、Dn的值分别为M1、M2、……、Mn,则由于它们全都满足三角形不等式(我们刚才已经假设M1到Mn是一组合法的解),则Bellman-Ford算法不会再更新任合D值,则最后得出的解就是M1、M2、……、Mn。

好了,现在知道了,初始值无穷大时,算出来的是D1、D2、……、Dn;初始值比较小的时候算出来的则是M1、M2、……、Mn。大家用的是同样的算法,同样的计算过程,总不可能初始值大的算出来的结果反而小吧。所以D1、D2、……、Dn就是M1、M2、……、Mn。

那么如果在一个未知数定死的情况下,要求其它所有未知数的最小值怎么办?只要反过来求最长路径就可以了。最长路径中的三角不等式与最短路径中相反:

d(v) >= d(u) + w(u, v)

也就是d(v) - d(u) >= w(u, v)

所以建图的时候要先把所有不等式化成大于等于号的。其它各种过程,包括证明为什么解出的是最小值的证法,都完全类似。

最近几天系统得学习了一些差分约束系统的原理,特此记录如下:

所谓差分约束系统,是指一组不定方程(A,x,T,b),其中A的每行有一个1,一个-1,其余为0,x为解向量,T为<=或>=组成的向量,b为约束矢量。具体来说,就是每行都具有 xi-xj >=|<= bi 的形式。约束的目标是使得目标函数xt-xs最大或最小。

这是典型的线性规划的个案,但是也可以转化为图论来做,利用最短路(或最长路)方法可以实现高效的解决方案。

SPFA的介绍:

http://blog.csdn.net/u013382399/article/details/44227003

这样最后再附上自己的代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
using namespace std;

const int maxn = 110;
const int INF = 0x3f3f3f3f;

struct Edge{
    int u,v,w,next;
}edge[maxn*maxn];

int d[maxn],in[maxn],next[maxn];
bool vis[maxn];
int tot;
int n,m;
queue<int> q;

void addEdge(int u,int v,int w){
    edge[tot].u = u;
    edge[tot].v = v;
    edge[tot].w = w;
    edge[tot].next = next[u];
    next[u] = tot++;
}
bool spfa(int size){

    int u,v;
    while(!q.empty()) q.pop();
    memset(in,0,sizeof(in));
    memset(vis,0,sizeof(vis));
    fill(d,d+size,INF);

    d[n+1] = 0;vis[n+1] = true;in[n+1] = 1;
    q.push(n+1);

    while(!q.empty()){
        u = q.front();vis[u] = false; q.pop();
        for(int i = next[u]; i != -1; i = edge[i].next){
            v = edge[i].v;
            if(d[u] + edge[i].w < d[v]){
                d[v] = d[u] + edge[i].w;
                if(!vis[v]){
                    vis[v] = true;
                    in[v] ++;
                    if(in[v] > size) return false;
                    q.push(v);
                }
            }
        }
    }
    return true;
}
int main(){
    int si,ni,ki;
    char oi[5];
    while(scanf("%d",&n)){
        if(n == 0) break;
        scanf("%d",&m);
        memset(next,-1,sizeof(next));
        tot = 0;

        ///自己创造一个超级原点,建立与其他点链接的边(使其与其他点相连接)
        ///因为SPFA没有办法处理不连通的图
        for(int i = 0; i <= n; i++){
            addEdge(n+1,i,0);///我让点n+1作为一个超级源点,其余各节点的边权是0
        }
        for(int i = 1; i <= m; i++){
            scanf("%d%d%s%d",&si,&ni,oi,&ki);
            if(oi[0] == 'g') addEdge(si+ni,si-1,-(ki+1));
            if(oi[0] == 'l') addEdge(si-1,si+ni,ki-1);
        }
        if (spfa(n + 2)) printf("lamentable kingdom\n");///总共有n+2个点
        else printf("successful conspiracy\n");
    }
    return 0;
}

有何疑问请留言,望各位大神走过路过~不吝赐教

时间: 2024-10-05 04:19:31

UVa 515 - King (差分约束系统 + SPFA求带负权最短路)的相关文章

SPFA 求带负权的单源最短路

int spfa_bfs(int s) { ///s表示起点: queue <int> q; memset(d,0x3f,sizeof(d)); ///d数组中存下的就是最短路径(存在的话) d[s] = 0; memset(c,0,sizeof(c));///c数组表示的是某一个节点的入队次数 memset(vis,0,sizeof(vis));///一如既往的标记数组 q.push(s); vis[s] = 1; c[s] = 1; ///顶点入队vis要做标记,另外要统计顶点的入队次数

spfa 算法模板 可求带负权边的最短路

它是队列优化的Bellman-Ford算法. 优化的原理是:下一次松弛操作时被更新dis的点其实与上一次被更新的点有关!如果上一次被更新的点有一条边指向某点V,那么在下一次,点V就是可能被更新dis的点. 和 Bellman-Ford 算法一样,它可以用来求带负权边的最短路,如果存在一个从源点可以到达的权重为负值的环路,则返回false表示无解决方案,因为可以不断在这个环路中循环使总代价越来越小:如果不存在则返回true. #include<iostream> #include<algo

Bellman-Ford 求含负权最短路

该算法详解请看   https://www.cnblogs.com/tanky_woo/archive/2011/01/17/1937728.html 单源最短路   当图中存在负权边时 迪杰斯特拉就不能用了 该算法解决了此问题 时间复杂度O(nm) 注意   图中含有负圈时不成立.当判定存在负圈时,这只说明s可以到达一个负圈,并不代表s到每个点的最短路都不存在. 另外,如果图中有其他负圈但是s无法达到这个负圈,该算法也无法找到,解决方法加一个节点(还不会...) 该算法可以用 队列 优化 名为

UVA 11478 Bellman-Ford+差分约束系统

[题意]: 给出一张有向图(信息为点数,边数,每条边的起点终点和权值),然后可以让你做任意次如下操作: 选择任意节点v和一个数值d,使以v为终点的边的权值减d,以v为起点的边的权值加d, 最后要满足两个条件:这些边的权值为非负,这些边中权值最小的边的权值尽量大.[知识点]: Bellman-Ford+差分约束系统[题解]: 差分约束系统:是判断不等式组有解的一种方法(具体原理还不甚理解,以后还会具体补充该文章) 例如有若干不等式形如xj-xi<=ak 那么以i为起点j为终点ak为权值建图,然后用

带负权图的单源最短路径算法:Bellman-Ford算法

算法简介 前面介绍过图的单源最短路径算法Dijkstra算法,然而Dijkstra算法无法判断含负权边的图的最短路.如果遇到负权,在没有负权回路存在时(负权回路的含义是,回路的权值和为负.)即便有负权的边,也可以采用Bellman-Ford算法正确求出最短路径. Bellman-Ford算法能在更普遍的情况下(存在负权边)解决单源点最短路径问题.对于给定的带权(有向或无向)图G=(V,E),其源点为s,加权函数 w是 边集 E 的映射.对图G运行Bellman-Ford算法的结果是一个布尔值,表

UVA11090 Going in Cycle!! (二分+SPFA判断有无负权)

I I U P C 2 0 0 6 Problem G: Going in Cycle!! Input: standard input Output: standard output You are given a weighted directed graph with n vertices and m edges. Each cycle in the graph has a weight, which equals to sum of its edges. There are so many

UVA 11478 bf+差分约束系统+二分逼近

Halum You are given a directed graph G(V, E) with a set of vertices and edges. Each edge (i, j) that connects some vertex i to vertex j has an integer cost associated with that edge. Define the operation Halum(v, d) to operate on a vertex v using an

UVA - 11478 Halum(差分约束系统)

题目大意:有一种操作(u,c),表示所有以u为终点的边的权值减去c,所有以u为起点的边权值加上c 最后要求所有的边的权值非负且尽量大 解题思路:最小且最大,二分,枚举边的最小权值,然后看是否符合 对于给出的所有有向线段(u,v,val) 所有对u和v的操作才会影响到这条边,对其他点的操作并不会影响到,所以可以将边分开出来讨论 假设对u的操作为d[u],对v的操作为d[v],那么这条边的权值就变成了 d[u] - d[v] + val 假设枚举的边权值为w,那么这条边就要满足 d[u] - d[v

POJ 1201 Intervals(差分约束+spfa 求最长路径)

题目链接:http://poj.org/problem?id=1201 Description You are given n closed, integer intervals [ai, bi] and n integers c1, ..., cn. Write a program that: reads the number of intervals, their end points and integers c1, ..., cn from the standard input, com