avatar
fireworks99
keep hungry keep foolish

POJ 3169 Layout(最短路解差分约束)

Description

N头牛(1~N)按序号排成一排

L个最大距离限制:某两头牛至多相距某个距离

D个最小距离限制:某两头牛至少相距某个距离

求第一头牛与第n头牛之间的最大距离

差分约束系统

如果一个系统由n个变量和m个约束条件组成,

形成m个形如 ai - aj ≤ k 的不等式(i,j∈[1,n],k为常数),

则称其为差分约束系统

举例

给定n个变量和m个不等式,

每个不等式的形式为 x[i] - x[j] <= a[k] (0 <= i, j < n, 0 <= k < m, a[k]已知),

求 x[i] - x[j] 的最大值。

例如当n = 4,m = 5,给出如下图所示的不等式组,求x3 - x0的最大值

picture

观察x3 - x0的性质,我们如果可以通过不等式的两两加和得到c个形如 x3 - x0 <= Ti 的不等式,那么 min{ Ti | 0 <= i < c } 就是我们要求的x3 - x0的最大值

x3 - x0 <= 8 (3)

x3 - x0 <= 9 (2)+(5)

x3 - x0 <= 7 (1)+(4)+(5)

要同时满足,答案取7

求差分约束系统转为求单源最短路

x[i] - x[j] <= a[k]

令dis[i] = x[i],令i = v, j = u, a[k] = w(j, i)

dis[v] - dis[u] <= w(u, v)
-> dis[v] <= dis[u] + w(u, v)

似最短路

前L条边:
    dis[v] - dis[u] <= w(u, v)
    add(u, v, w);
后D条边:
    dis[v] - dis[u] >= w(u, v)
    统一采用 <= (两边同乘 -1)
    dis[u] - dis[v] <= - w(u, v)
    add(v, u, -w);
隐藏边:
    dis[i + 1] - dis[i] >= 0
    dis[i] - dis[i + 1] <= 0
    add(i + 1, i, 0);

相应转化后,要求1到n最大距离

最大对应到题目上,(L个)每个最大距离都取等号,才能对应“最大”

那为什么是求最短路(最小距离)呢?

x3 - x0 <= 8

x3 - x0 <= 9

x3 - x0 <= 7

这里多条路只能选最短的那条(因为要同时满足三个不等式),这就对应起来了

补充

  1. 存在负环:dis[n]可无限小, -1
  2. 图不连通:dis[n] == INF, -2

Code

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

const int N = 1005;
const int inf = 0x3f3f3f3f;

struct node///存放“边”
{
    int from, to, w, pre;
} a[N * N << 1];

int head[N], cnt, dis[N], times[N], tot, sum, n, L, D;
bool vis[N];///vis[i]:0表示i不在队列里,1表示i在队列里

void init()///受n影响,应安排在n被赋值之后
{
    cnt = 0;
    for(int i = 0; i <= n; ++i)
        dis[i] = inf, times[i] = 0, vis[i] = 0, head[i] = -1;
    return ;
}

void add(int from, int to, int w)
{
    a[cnt].from = from;
    a[cnt].to = to;
    a[cnt].w = w;
    a[cnt].pre = head[from];
    head[from] = cnt;
    cnt++;
}

bool spfa(int start)
{
    deque<int> q;
    dis[start] = 0;///到自己的距离为0
    vis[start] = 1;
    q.push_front(start);
    tot = 1, sum = 0;
    while(q.size())
    {
        int first = q.front();
        q.pop_front();
        vis[first] = 0;
        tot--;
        sum -= dis[first];

        for(int i = head[first]; ~ i; i = a[i].pre)
        {
            int t = a[i].to;
            if(dis[t] > dis[first] + a[i].w)
            {
                dis[t] = dis[first] + a[i].w;
                if(!vis[t])
                {
                    vis[t] = 1;         ///极值优化             ///平均值优化
                    if(q.empty() || dis[t] > dis[q.front()] || dis[t] * tot >= sum)
                        q.push_back(t);
                    else
                        q.push_front(t);
                    sum += dis[t];
                    tot++;
                    if(++times[t] > n)
                        return 0;
                }
            }
        }
    }
    return 1;
}

int main()
{
    scanf("%d%d%d", &n, &L, &D);
    init();
    int u, v, w;
    for(int i = 0; i < L; ++i)
    {
        scanf("%d%d%d", &u, &v, &w);
        add(u, v, w);
    }
    for(int i = 0; i < D; ++i)
    {
        scanf("%d%d%d", &u, &v, &w);
        add(v, u, -w);
    }
    for(int i = 1; i < n; ++i)
        add(i + 1, i, 0);
    if(spfa(1))
    {
        if(dis[n] == inf)
            cout << "-2" << '\n';
        else
            cout << dis[n] << '\n';
    }
    else
        cout << "-1" << '\n';
    return 0;
}

部分原文来自:

http://www.cppblog.com/menjitianya/archive/2015/11/19/212292.html

https://blog.csdn.net/my_sunshine26/article/details/72849441

Site by Baole Zhao | Powered by Hexo | theme PreciousJoy