1. 程式人生 > 實用技巧 >【最短路/線性差分約束】Layout POJ - 3169

【最短路/線性差分約束】Layout POJ - 3169

Layout POJ - 3169

題意:

\(n\)頭奶牛按序號\(1~n\)排成一行,允許多頭奶牛站在同一個位置上。給定\(ML\)行關係,每行三個整數\(u,v,dis\),表示奶牛\(u\)與奶牛\(v\)的距離不大於\(dis\);再給定\(MD\)行關係,每行三個整數\(u,v,dis\),表示奶牛\(u\)與奶牛\(v\)的距離不小於\(dis\)。求奶牛\(n\)與奶牛\(1\)最大可能距離

如果最大可能距離不存在,輸出\(-1\);如果最大可能距離可以是任意值,輸出\(-2\);否則輸出這個距離。

思路:

線性差分約束,所求的是最大值。因此答案就是從節點\(1\)到節點\(n\)

最短路

所給出的約束關係都應該為\(u-v≤d\)的形式。

對於其中\(MD\)行約束關係,給出的是\(u-v≥d\),因此等號兩邊同乘\(-1\)變形得\(v-u≤-d\)

由此可見根據約束關係所建的圖包含負權邊,即可能存在負權環,對應的是最大可能距離不存在的情況;如果奶牛\(n\)與奶牛\(1\)之間沒有直接或間接的約束關係,也就是節點\(n\)不可到達,對應的是最大可能距離可以是任意值的情況。

const int INF = 0x3f3f3f3f3f;
const int maxn = 1000 + 10;

int num = 0;
int n, m;
int head[maxn], inq_cnt[maxn];
LL d[maxn];
bool inq[maxn];

struct Edge {
    int next, to;
    LL dis;
}edges[maxn*20];

void add_edge(int from, int to, LL dis) {
    num++;
    edges[num].next = head[from];
    edges[num].to = to;
    edges[num].dis = dis;
    head[from] = num;
}

bool spfa(int s) {
    queue<int> q;
    d[s] = 0;
    inq[s] = true;
    q.push(s);
    inq_cnt[s]++;
    while (!q.empty()) {
        int u = q.front(); q.pop();
        inq[u] = false;
        for (int i = head[u]; i != 0; i = edges[i].next) {
            Edge& e = edges[i];
            if (d[u] < INF && d[u] + e.dis < d[e.to]) {
                d[e.to] = d[u] + e.dis;
                if (!inq[e.to]) {
                    if (inq_cnt[e.to] > n) return false;
                    q.push(e.to);
                    inq[e.to] = true;
                    inq_cnt[e.to]++;
                }
            }
        }
    }
    return true;
}

void init() {
    num = 0;
    memset(edges, 0, sizeof(edges));
    memset(inq_cnt, 0, sizeof(inq_cnt));
    memset(inq, false, sizeof(inq));
    memset(head, 0, sizeof(head));
    for (int i = 0; i <= n; i++) d[i] = INF;
}

int main()
{
    ios::sync_with_stdio(false);
  //  FILE* stream1;
  //  freopen_s(&stream1, "input.txt", "r", stdin);
  //  freopen_s(&stream1, "output.txt", "w", stdout);
   // int t; cin >> t; for(int kase=1;kase<=t;kase++) {
    int ml, md;
    cin >> n >> ml >> md;
    init();
    for (int i = 1; i <= ml; i++) {
        int u, v;
        LL dis;
        cin >> u >> v >> dis;
        //v-u<=dis;
        add_edge(u, v, dis);
       // printf("%d→%d:%lld\n", u, v, dis);
    }
    for (int i = 1; i <= md; i++) {
        int u, v;
        LL dis;
        cin >> u >> v >> dis;
        //v-u>=dis
        //u-v<=-dis
        add_edge(v, u, -dis);
      //  printf("%d→%d:%lld\n", v, u, -dis);
    }

    if (!spfa(1)) cout << "-1";
    else {
        if (d[n] == INF) cout << "-2";
        else cout << d[n] - d[1];
    }
   // }
    return 0;
}