POJ - 1201 Intervals 【差分约束 + 最长路模型】

传送门
// 题意:
对于一个序列,有n个描述,[ai,bi,ci]分别表示在区间[ai,bi]上,至少有ci个数属于该区间, 输出满足这n个条件的最短的序列(即包含的数字个数最少) 包含的最少的个数是多少.

// 思路: 首先还是一个数轴来表示, 但是这的点并不再是单调的点, 而是应该用区间的形式. 所以设d[i] 表示 [0, i] 上有多少个数属于该区间. 所以对于输入数据ai bi ci 我们用d[bi] - d[ai-1] >= ci, 然后我们还要注意一些隐藏的条件, 那就是一个元素所在的区间取得的数的关系, 即d[k] - d[k-1] >= 0 && <= 1, 表示一个点表示的区间最多选一个点, 最少不选. 注意就是0的情况d[0] - d[-1] , 由于出现了负数, 我们将所有的点一起左移一个单位即可, 然后对所有的不等式建图即可, 我们要求的就是这些区间中最大的点ed 到 最小的点st 的最长路. (注意这里的点都是左移过的点)

AC Code

const int maxn = 5e4+5;
const ll INF = 1e18;
int cas = 1;
struct node
{
    int to, next, w;
}e[maxn*3];

int dis[maxn];
int head[maxn], cnt, times[maxn];
bool vis[maxn];
void add(int u,int v,ll w)
{
    e[cnt] = (node){v,head[u],w};
    head[u] = cnt++;
}
void init() {
    cnt = 0 ;
    Fill(head , -1);
}
int n;
bool spfa(int st,int ed)
{
    queue<int >q;
    Fill(vis, 0); Fill(times, 0);
    for (int i = 1 ; i <= n ; i ++) dis[i] = -inf;
    dis[st] = 0; vis[st] = true; times[st]++;
    q.push(st);
    while(!q.empty()){
        int u = q.front();
        q.pop();
        vis[u] = false;
        for(int i = head[u] ; ~i ; i = e[i].next){
            int to = e[i].to;
            if(dis[to] < dis[u] + e[i].w){
                dis[to] = dis[u] + e[i].w;
                if(times[to] > n)
                    return false;
                else if(!vis[to]){
                    times[to]++;
                    vis[to] = true;
                    q.push(to);
                }
            }
        }
    }
    return true;
}

void solve()
{
    scanf("%d", &n);
    init();
    int st = inf, ed = 0;
    for (int i = 1 ; i <= n ; i ++) {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        u++; v++;
        add(u-1, v, w);
        st = min(u-1, st);
        ed = max(v, ed);
    }
    for (int i = st + 1 ; i <= ed ; i ++) {
        add(i, i-1, -1);
        add(i-1, i , 0);
    }
    spfa(st, ed);
    printf("%d\n", dis[ed]);
}

你可能感兴趣的:(差分约束系统)