首页 > 技术文章 > poj Integer Intervals

zzz-hhh 2020-07-19 09:39 原文

传送门
区间上的差分约束问题

思路

\(d[x]-d[y]<=/>= c\) ,则由y向x连一条权值为\(c\)的边
\(d[i]\)为从1号点到i最少选出的数的个数
根据题目要求,对于区间\([l,r]\),得约束条件\(1:d[r]-d[l-1]>=2\)
为保证连续性,隐含约束条件\(2:0<=d[i]-d[i-1]<=1\)
即每个点要么不选,要么只能选一次
设总区间\([s,t]\)
那么目的就是 \(d[t]-d[s]>=ans\)
\(d[t]>=ans+d[s]\),所以\(spfa\)跑最长路
因为题目中,输入数据端点可能有\(0\),所以我们将所有的数整体后移一位

code

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 10002
using namespace std;
int n, minn = N, maxn;
struct node {
    int to,next,w;
}edge[N << 2];
int dis[N], front[N], tot;
bool v[N];

int read() {
	int s = 0, f = 0; char ch = getchar();
	while (!isdigit(ch)) f |= (ch == '-'), ch = getchar();
	while (isdigit(ch)) s = s * 10 + (ch ^ 48), ch = getchar();
	return f ? -s : s;
}

void add(int u, int v, int w) {
    edge[++tot].to = v;
    edge[tot].next = front[u];
    front[u] = tot;
    edge[tot].w = w;
}

void spfa() {
    memset(dis, -1, sizeof dis);
	queue<int>q; q.push(minn);
    v[minn]=true, dis[minn]=0;
    while (!q.empty()) {
        int now = q.front();
        q.pop(), v[now] = false;
        for (int i = front[now]; i; i = edge[i].next) {
            int to = edge[i].to;
            if (dis[to] < dis[now] + edge[i].w) {
                dis[to] = dis[now] + edge[i].w;
                if (!v[to]) v[to] = true, q.push(to);
            }
        }
    }
    printf("%d", dis[maxn]);
}

int main() {
	n = read();
    for (int i = 1, x, y; i <= n; i++) {
        x = read(), y = read(); y++;
        add(x, y, 2);
        minn = min(x, minn);
        maxn = max(maxn, y);
    }
    for (int i = minn; i < maxn; i++) {
        add(i, i + 1, 0);
        add(i + 1, i, -1);
    }
    spfa();
    return 0;
}

推荐阅读