「POJ1201」Intervals - 差分约束

->戳我进原题

Intervals


Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 30393 Accepted: 11768


Description

You are given n closed, integer intervals [ai, bi] and n integers c1, ..., cn.
Write a program that:
reads the number of intervals, their end points and integers c1, ..., cn from the standard input,
computes the minimal size of a set Z of integers which has at least ci common elements with interval [ai, bi], for each i=1,2,...,n,
writes the answer to the standard output.

Input

The first line of the input contains an integer n (1 <= n <= 50000) -- the number of intervals. The following n lines describe the intervals. The (i+1)-th line of the input contains three integers ai, bi and ci separated by single spaces and such that 0 <= ai <= bi <= 50000 and 1 <= ci <= bi - ai+1.

Output

The output contains exactly one integer equal to the minimal size of set Z sharing at least ci elements with interval [ai, bi], for each i=1,2,...,n.

Sample Input

5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1

Sample Output

6

思路

典型差分约束题,这个东西着实比较抽象,所以我调了好长时间才过2333。
这个题大概是这样的:

  • 给定 \(n\) 个闭区间 \([ai,bi](1≤n,0≤ai,bi≤50000)\)\(n\) 个整数 \(ci(1≤i≤n)\)

  • 你需要构造一个整数集合 \(Z\),使得 \(∀i∈[1,n]\)\(Z\) 中满足 \(ai≤x≤bi\) 的整数 \(x\) 不少于 \(ci\)个。

  • 求这样的整数集合 \(Z\) 最少包含多少个数。

\(s[k]\) 表示 \(0\)\(k\) 之间最少选出多少个整数。根据题意,有 \(s[bi]−s[ai−1]≥ci\) 个,这很明显是一个差分约束系统的模型。
不过,我们还要增加一些隐含的条件,才能保证求出的解是有意义的:

1) \(s[k]−s[k−1]≥0\) \(0\)\(k\) 之间选出的书肯定在 \(0\)\(k−1\) 内。

2) \(s[k]−s[k−1]≤1\) 每个数只能被选一次。可变形为 \(s[k−1]−s[k]≥−1\)

代码

#include<cstdio>
#include<cctype>
#include<iostream>
#include<queue>
#include<cstring>
#define rg register
using namespace std;
inline int read(){
    rg int f = 0, x = 0;
    rg char ch = getchar();
    while(!isdigit(ch)) f |= (ch == '-'), ch = getchar();
    while( isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
    return f? -x: x;
}
const int N = 50010;
const int inf = 0x7f7f7f7f;
int n, head[N], tot, dis[N], minn = inf, maxn = -inf;
bool vis[N];
struct edge{
    int to, nxt, w;
}e[N << 4];
inline void add(rg int u, rg int v, rg int w){
    e[++tot].nxt = head[u];
    e[tot].to = v;
    e[tot].w = w;
    head[u] = tot;
}
inline void spfa(){
    queue<int > q;
    for(rg int i = minn; i <= maxn; ++i)    dis[i] = -inf;//dis一定要是负无穷 
    dis[minn] = 0;
    q.push(minn);
    while(!q.empty()){
        int u = q.front();
        q.pop();
        vis[u] = false;
        for(rg int i = head[u]; i; i = e[i].nxt){
            int v = e[i].to;
            if(dis[v] < dis[u] + e[i].w){
                dis[v] = dis[u] + e[i].w;
                if(!vis[v]){
                    vis[v] = true;
                    q.push(v);
                }  
            }
        }
    }
}       `   
signed main(){
    n = read();
    for(rg int i = 1; i <= n; ++i){
        int a = read(), b = read(), c = read();
        add(a - 1, b, c);
        minn = min(minn, a - 1);
        maxn = max(maxn, b);
    }
    for(rg int i = minn; i <= maxn; ++i){
        add(i - 1, i, 0);
        add(i, i - 1, -1);
    }
    spfa();
    printf("%d", dis[maxn]);
    return 0;
}

转载于:https://www.cnblogs.com/horrigue/p/9705770.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值