POJ 1201 Intervals(差分约束 区间约束模版)

关于差分约束详情可阅读:http://www.cppblog.com/menjitianya/archive/2015/11/19/212292.html

题意:

给定n个区间[L,R], 每个区间至少放w个球, 问最后整个区间最少要放多少个球。

分析:

假设d[i] 是 [1,i] 至少有多少个点被选中, 特殊地, d[0] = 0。 每个区间的描述可以转化为d[R] - d[L-1] >= w。(因为d[L]也要选中, 左闭右闭区间, 所以要减d[L-1])
因为d[i]描述了一个求和函数,所以对于d[i]和d[i-1]其实是有自身限制的,考虑到每个点有选和不选两种状态,所以d[i]和d[i-1]需要满足以下不等式: 0 <= d[i] - d[i-1] <= 1 (即第i个数选还是不选)

这样, 我们就有了3个约束不等式

d[R] - d[L-1] >= w  (1)

d[i] - d[i-1] >= 0      (2)

d[i-1] - d[i] >= -1     (3)

求出d[min-1]到d[max]的最长路, d[max] 就是这个区间最少要放多少个球。

#include<cstdio>
#include<string>
#include<iostream>
#include<cstring>
#include<vector>
#include<map>
#include<queue>
#define rep(i,a,b) for(int i = a; i < b; i++)
#define _rep(i,a,b) for(int i = a; i <= b; i++)
using namespace std;
const int maxn = 50000 + 7;
struct edge{
    int to , d;
    edge(int _to, int _d): to(_to), d(_d){}
};
vector<edge> G[maxn];
/*
差分约束系统
对于每个不等式 x[i] - x[j] >= a[k],对结点 j 和 i 建立一条 j -> i的有向边,边权为a[k],求x[n] - x[1] 的最大值就是求 1 到n的最长路。

假设d[i] 是 [1,i] 至少有多少个点被选中, 特殊地, d[0] = 0;
每个区间的描述可以转化为d[R] - d[L-1] >= w

因为d[i]描述了一个求和函数,所以对于d[i]和d[i-1]其实是有自身限制的,考虑到每个点有选和不选两种状态,
所以d[i]和d[i-1]需要满足以下不等式:  0 <= d[i] - d[i-1] <= 1   (即第i个数选还是不选)
*/

void add_edge(int u, int v, int d){
    G[u].push_back(edge(v, d));
}
int n, a, b;
bool vis[maxn];
int dis[maxn];
int spfa(int s){
    memset(vis,0, sizeof(vis));
    for(int i = a; i <= b; i++) dis[i] = -1e9;
    queue<int> q;
    vis[s] = 1;
    dis[s] = 0;
    q.push(s);
    while(!q.empty()){
        int u = q.front();
        for(int i = 0; i < G[u].size(); i++){
            int v = G[u][i].to, d = G[u][i].d;
            if(dis[u] + d > dis[v]){//求最长路
                dis[v] = dis[u] + d;
                if(!vis[v]){
                    vis[v] = 1;
                    q.push(v);
                }
            }
        }
        vis[u] = 0;
        q.pop();
    }
    return dis[b];
}
int main(){
//    freopen("1.txt","r", stdin);
    while(~scanf("%d", &n)){
        a = 1e9 + 7, b = -1e9 + 7; //求这个区间的最小值, 最大值
        rep(i,0,maxn) G[i].clear();
        rep(i,0,n){
            int L, R, w;
            scanf("%d %d %d", &L, &R, &w);
            a = min(a, L), b = max(b, R);
            add_edge(L-1,R,w);//对结点 j 和 i 建立一条 j -> i的有向边,边权为a[k]
        }
        _rep(i,a,b){
            add_edge(i-1,i,0);          //d[i] - d[i-1] >= 0
            add_edge(i,i-1,-1);          //d[i] - d[i-1] <= 1 不等式标准化成 d[i-1] - d[i] >= -1
        }
        puts("");
        printf("%d\n",spfa(a-1));
    }
}

原文地址:https://www.cnblogs.com/Jadon97/p/8343065.html

时间: 2024-10-11 02:17:43

POJ 1201 Intervals(差分约束 区间约束模版)的相关文章

POJ 1201 Intervals 差分约束

http://poj.org/problem?id=1201 TLE了很久,因为用了cin..... 思路和其他差分约束差不多,http://www.cppblog.com/menjitianya/archive/2015/11/19/212292.html 如果区间[a, b]中至少有c个元素,如果用上面的博客,那么说明xa - xb >= c,但是注意这里是闭区间,xa - xb是不包括b这个点的, 就比如用了[a, b]有c个元素,[b, d]有x个,那么ans = c + x - 1个,

poj 1201 Intervals 差分约束系统

题目链接:http://poj.org/problem?id=1201 题意:给定n(1<= n <= 50000)个 闭区间,每个区间后面带一个值 Ci, 问集合Z个数的最小值使得在每个区间中的数的个数 “不少于Ci”? 思路: S[i] 表示 小于等于i 的个数,这样可以直接按照输入建立不等式之后转化为有向网即可: 需要注意的是 在原始的两个不等式 S[i-1] - s[i] <= 0 和 s[i-1] - s[i] <= 1不宜在建边时就加入,这会使得有向网络中的边数达到3*

poj 1201 Intervals(差分约束系统)(困难)

Intervals Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 23205   Accepted: 8764 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 po

POJ 1201 Intervals(图论-差分约束)

Intervals Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 20779   Accepted: 7863 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 po

POJ 1201 Intervals(差分约束)

[题目链接] http://poj.org/problem?id=1201 [题目大意] 告诉你一个区间至少要选定的数字的个数,给出n个区间的需求 问最少选取几个数字可以满足所有的需求 [题解] 对于区间[a,b]建立不等式Sb+1-Sa>=c,最后要求最小化Smax, 结合基础条件Si+1-Si>=0,Si-Si+1>=-1,构造差分约束系统求最长路就是答案. [代码] #include <cstdio> #include <algorithm> #includ

POJ 1201 Intervals(差分约束+spfa 求最长路径)

题目链接:http://poj.org/problem?id=1201 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, com

poj 1201 Intervals【差分约束+spfa】

设s为前缀和,首先显然的条件是\[ s_{bi}-s_{ai-1}>=c \],然后隐含的是\[ s_i-s_{i-1}>=0 s_i-s_{i-1}<=1 \] 然后根据差分约束,就是连边(bi,ai-1,-li),(i-1,i,1),(i,i-1,0) spfa跑最长路最后输出相反数即可,注意n是起点,min是终点,跑最短路(不会有负环) #include<iostream> #include<cstdio> #include<queue> usi

POJ 1201 Intervals (差分约束,最短路)

题意:假设有一个自然数区间[0,50000],要从中挑出一些自然数出来,但是现在不知道整个区间究竟要挑多少个出来,只知道一部分闭区间[a,b]内至少要挑多少个,所知道的有n个闭区间.问至少要挑出多少个? 思路: 对于所给的区间 cnt[b-a]>=k这可以保证了该区间内个数不少于k.但是由于两边都是闭区间,所以要变cnt[b-(a-1)]>=k,表示b到a之间的个数.也就是说,转成式子是b-(a-1)>=k,变换一下为(a-1)-b<=-k,就满足常见的式子b-a<=k啦,可

POJ 2101 Intervals 差分约束

Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 27746   Accepted: 10687 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