首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

POJ 1364 King:差分約束系統與負環判斷

     編輯:關於C++

問題重述

給定長度為 n(≤ 100)的整數序列 S,以及 m(≤ 100)條子序列和約束:
S[si] + … + S[si+ni] < ki 或 > ki。
判斷是否存在滿足所有約束的序列 S。

轉化為差分約束

令前綴和 P[i] = S[1] + … + S[i],P[0] = 0。
子序列和 = P[s+n] − P[s−1]。

  • lt(< k)→ P[s+n] − P[s−1] ≤ k−1 → 有向邊 (s−1) → (s+n) 權值 k−1。
  • gt(> k)→ P[s+n] − P[s−1] ≥ k+1 → P[s−1] − P[s+n] ≤ −k−1 → 有向邊 (s+n) → (s−1) 權值 −k−1。

共 n+1 個節點(0…n)。加入超級源點 n+1,向所有節點連邊權 0,確保圖連通。

判斷可行性:SPFA 檢測負環

若圖中存在負環,則差分約束系統無解,輸出 successful conspiracy;否則輸出 lamentable kingdom。

SPFA 關鍵代碼

bool spfa() {
    queue<int> q; vector<int> cnt(N+2, 0), inq(N+2, 0), dis(N+2, INF);
    dis[super] = 0; q.push(super); inq[super] = 1; cnt[super] = 1;
    while (!q.empty()) {
        int u = q.front(); q.pop(); inq[u] = 0;
        for (auto &e : G[u]) {
            int v = e.to;
            if (dis[v] > dis[u] + e.w) {
                dis[v] = dis[u] + e.w;
                if (!inq[v]) {
                    q.push(v); inq[v] = 1;
                    if (++cnt[v] > N+1) return false; // 負環
                }
            }
        }
    }
    return true;
}

完整 AC 代碼

#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
using namespace std;
const int INF = 0x3f3f3f3f;
struct Edge { int to, w; };
int main() {
    int n, m;
    while (scanf("%d", &n) && n) {
        scanf("%d", &m);
        vector<vector<Edge>> G(n + 2);
        auto add = [&](int u, int v, int w) { G[u].push_back({v, w}); };
        for (int i = 0; i < m; ++i) {
            int s, ni, k; char op[3];
            scanf("%d%d%s%d", &s, &ni, op, &k);
            if (op[0] == 'g') // gt
                add(s + ni, s - 1, -(k + 1));
            else // lt
                add(s - 1, s + ni, k - 1);
        }
        int super = n + 1;
        for (int i = 0; i <= n; ++i) add(super, i, 0);
        // SPFA
        vector<int> dis(n + 2, INF), cnt(n + 2, 0), inq(n + 2, 0);
        queue<int> q; dis[super] = 0; q.push(super); inq[super] = 1; cnt[super] = 1;
        bool ok = true;
        while (!q.empty() && ok) {
            int u = q.front(); q.pop(); inq[u] = 0;
            for (auto &e : G[u]) {
                int v = e.to;
                if (dis[v] > dis[u] + e.w) {
                    dis[v] = dis[u] + e.w;
                    if (!inq[v]) {
                        q.push(v); inq[v] = 1;
                        if (++cnt[v] > n + 1) { ok = false; break; }
                    }
                }
            }
        }
        puts(ok ? "lamentable kingdom" : "successful conspiracy");
    }
    return 0;
}

複雜度

節點 ≤ 101,邊 ≤ 100 + 101,SPFA 極快。多測試案例總時間遠小於限制。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved