1. 程式人生 > 實用技巧 >poj 1201 Intervals 差分約束系統

poj 1201 Intervals 差分約束系統

Poj 1201 Intervals

題目連結

​ 差分約束系統。

​ 設\(s[x]\)表示從橫座標為0到橫座標為\(x\)的最少點數,所以求出\(s[maxn]\)就好了。(\(maxn\)為橫座標最大的數)

​ 根據每個區間最少的點數,我們可以得到:\(s[y] - s[x - 1] >= c\)

​ 另外還要是後面的大於等於前面的:\(s[i] - s[i - 1] >= 0\)

​ 因為相鄰的最多隻差一,所以:\(s[i] - s[i - 1] <= 1\)

​ 還有:dij一定不能用在帶有負邊權的圖中!!!這道題只能用SPFA。(我傻不愣登的調了一上午dij)

#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>

#define int long long

using namespace std;

inline long long read() {
    long long s = 0, f = 1; char ch;
    while(!isdigit(ch = getchar())) (ch == '-') && (f = -f);
    for(s = ch ^ 48;isdigit(ch = getchar()); s = (s << 1) + (s << 3) + (ch ^ 48));
    return s * f;
}

const int N = 5e5 + 5, inf = 1e9;
int n, maxn, minn, cnt;
int in[N], vis[N], dis[N], head[N];
struct edge { int to, nxt, val; } e[N << 2];

void add(int x, int y, int z) {
    e[++cnt].nxt = head[x]; head[x] = cnt; e[cnt].to = y; e[cnt].val = z;
}

void run_dij() {
    memset(dis, 128, sizeof(dis));
    queue <int> q;
    q.push(minn); dis[minn] = 0;
    while(!q.empty()) {
        int x = q.front(); q.pop(); in[x] = 0;
        for(int i = head[x]; i ; i = e[i].nxt) {
            int y = e[i].to;
            if(dis[y] < dis[x] + e[i].val) {
                dis[y] = dis[x] + e[i].val;
                if(!in[y]) in[y] = 1, q.push(y);
            }
        }
    }
}

signed main() {

    n = read(); maxn = -inf; minn = inf;
    for(int i = 1, x, y, z;i <= n; i++) {
        x = read() + 1, y = read() + 1, z = read(), add(x - 1, y, z);
        maxn = max(maxn, max(x - 1, y));
        minn = min(minn, min(x - 1, y));
    }
    for(int i = minn;i <= maxn; i++) {
        if(i != minn) add(i - 1, i, 0), add(i, i - 1, -1);
    }

    run_dij();

    printf("%lld", dis[maxn]);

    return 0;
}