POJ - 3169 Layout 【spfa解决差分约束问题】

版权声明:如需转载,记得标识出处 https://blog.csdn.net/godleaf/article/details/87907527

题目链接:http://poj.org/problem?id=3169

根据给出的样例,我们能得到下面几个不等式。(d表示离点1的距离)

d[2] - d[3] <= 10

d[4] - d[2] <= 20

d[3] - d[2] >= 3

第三个不等式通过移项能得到 d[2] - d[3] <= -3

 再来看看spfa的松弛不等式 d[v] > d[u]+w。从最短路的角度来看,spfa是根据这个不等式来保证每次都能更新得到一个源点到v的最短距离。假设d[v],和d[u]都已经是最短距离了,那么对于任何一条边的权值w都有 d[v]-d[u] <= w。

也就是说当最短路径求出来后,对于所有的点,都满足 d[v] - d[u] <= w这个约束条件,这也是spfa能解决差分约束问题的原理。

只要我们把 w 当作一个约束条件为本题构建一个图,通过求最短路径的方式求解问题就能得出答案。

构图的过程中要注意一个问题,约束条件可能有很多,也可能一个都没有,所以构建出来的图有可能是不连通的,这里就要运用一个隐藏的约束条件使得构建的整个图是一个连通图,因为cow都是按顺序排列成一条线的,所以d[1] <= d[2],这个是肯定的,所以就有 d[2] - d[1] >= 0,因为N个点,每相邻的两个点都有这个约束条件,这就能保证构建的图是一个连通图。

另外,当图有负环时说明题目无解输出-1,当 d[N] == INF,说明题目约束条件不足以限制 1到N之间的距离。

#include <iostream>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>

using namespace std;

#define lson (cur<<1)
#define rson (cur<<1|1)
typedef long long ll;
typedef pair<int, int> pii;

const int INF = 0x3f3f3f3f;
const int Maxn = 1e6+10;
const int Mod = 1e9+7;

struct Edge {
    int to, cost;
    Edge(int x = 0, int y = 0):to(x), cost(y) {};
} edge[Maxn*2+1000];

vector <int> G[1010];
bool vis[1010];
int cnt[1010], d[1010];

bool spfa(int V, int N) {
    for(int i = 0; i <= N; ++i) {
        d[i] = INF; vis[i] = false;
        cnt[i] = 0;
    }
    d[V] = 0; vis[V] = true;
    queue<Edge> qu;
    qu.push(Edge(V, 0));

    while (!qu.empty()) {
        int v = qu.front().to; qu.pop();
        vis[v] = false;

        for(int i = 0; i < G[v].size(); ++i) {
            Edge &e = edge[G[v][i]];
            if(d[e.to] > d[v]+e.cost) {
                d[e.to] = d[v]+e.cost;
                if(!vis[e.to]) {
                    vis[e.to] = true;
                    cnt[e.to]++;
                    if(cnt[e.to] > N) return false;
                    qu.push(Edge(e.to, d[e.to]));
                }
            }
        }
    }
    return true;
}

int main(void)
{
    int N, ML, MD;
    scanf("%d%d%d", &N, &ML, &MD);
    int u, v, w;
    for(int i = 0; i < ML; ++i) {
        scanf("%d%d%d", &u, &v, &w);
        edge[i].to = v; edge[i].cost = w;
        G[u].push_back(i);
    }
    for(int i = ML; i < ML+MD; ++i) {
        scanf("%d%d%d", &u, &v, &w);
        edge[i].to = u; edge[i].cost = -w;
        G[v].push_back(i);
    }
    int cnt = ML+MD;
    for(int i = 2; i <= N; ++i) {
        edge[cnt].to = i-1; edge[cnt].cost = 0;
        G[i].push_back(cnt); cnt++;
    }
    if(spfa(1, N)) {
        if(d[N] == INF) printf("-2\n");
        else printf("%d\n", d[N]);
    } else printf("-1\n");
    return 0;
}

猜你喜欢

转载自blog.csdn.net/godleaf/article/details/87907527
今日推荐