POJ 1201 差分约束

来源:互联网 发布:微信刷屏软件 编辑:程序博客网 时间:2024/06/09 19:08

Intervals
Time Limit: 2000MS Memory Limit: 65536KTotal Submissions: 19967 Accepted: 7559

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

53 7 38 10 36 8 11 3 110 11 1

Sample Output

6
题意:

题目描述:
给定n 个整数闭区间[ai, bi]和n 个整数c1, …, cn。编程实现:
1) 以标准输入方式读入闭区间的个数,每个区间的端点和整数c1, …, cn;
2) 求一个最小的整数集合Z,满足|Z∩[ai,bi]|>=ci,即Z 里边的数中范围在闭区间[ai,bi]
的个数不小于ci 个,i = 1, 2, …, n。
3) 以标准输出方式输出答案。
输入描述:
图论算法理论、实现及应用
- 200 -
输入文件包含多个测试数据,每个测试数据的第一行为一个整数n(1≤n≤50000) - 表示区
间的个数。接下来n 行描述了这n 个区间:第i+1 行包含了3 个整数ai, bi, ci,用空格隔开,0≤
ai≤bi≤50000,1≤ci≤bi - ai + 1。
输入数据一直到文件尾。

输出描述:
对输入文件中的每个测试数据,输出一个整数,为最小的整数集合Z 的元素个数|Z|,整数集
合Z 满足:Z 里边的数中范围在闭区间[ai,bi]的个数不小于ci 个,i = 1, 2, …, n。


分析:
该题目可建模成一个差分约束系统。以样例输入中的测试数据为例进行分析。
设S[i]是集合Z 中小于等于i 的元素个数,即S[i] = | { s | s∈Z, s<=i } |。则有以下不等式组:
① Z 集合中范围在[ai, bi]的整数个数即S[bi] – S[ai-1]至少为ci,得不等式组①(即约束条件
①):
S[bi] – S[ai-1] >= ci,转换成:S[ai-1] – S[bi] <= -ci。
S2 – S7 <= -3
S7 – S10 <= -3
S5 – S8 <= -1
S0 – S3 <= -1
S9 – S11 <= -1
根据实际情况,还有两个约束条件:
② S[i] – S[i-1] <= 1;
③ S[i] – S[i-1] >= 0,即S[i-1] – S[i] <= 0
最终要求的是什么?设所有区间右端点的最大值为mx,如该测试数据中mx = 11,所有区间
左端点的最小值为mn,如该测试数据中mn = 1,mn – 1 = 0,最终要求的是S[mx] – S[mn-1]的
最小值,即求S11 – S0 >= M 中的M,转换成S0 – S11 <= -M,即要求源点S11 到S0 的最短路
径长度,长度为-M。
假设最终求得的各顶点到源点S11 的最短路径长度保存在数组dist[ ]中,那么-M = dist[0] –
dist[11],即M = dist[11] – dist[0],即为所求。
与例4.13 直接根据约束条件构造网络图求解最短路径的方法不同的是,由于第②、③个约束
条件中的不等式有2*(mx – mn + 1)个,再加上约束条件①,构造的边数最多可达3*50000 条,所
以将所有的约束条件转换成图中的边,不是个好方法。
更好的方法是:
1) 先仅仅用约束条件①构造网络图,各顶点到源点的最短距离初始为0,这是因为Si – Smx
<= 0,所以源点到各顶点的最短距离肯定是小于0 的。注意本题中源点是S[mx]。
第4 章 最短路径问题
- 201 -
2) 即刻用Bellman-Ford 算法求各顶点到源点的最短路径(注意Bellman-Ford 算法的思想),
在每次循环中,约束条件①判断完后再加上约束条件②和③的判断。
a) 约束条件②的判断:
S[i] <= S[i-1] + 1 等效于 S[i] – S[mx] <= S[i-1] – S[mx] + 1。
假设dist[i]为源点mx 到顶点Si 的最短路径,那么S[i] – S[mx]就是dist[i],S[i-1] – S[mx] + 1
就是dist[i-1] + 1,即如果顶点Si 到源点的最短路径长度大于Si-1 到源点的最短路径长度加1,则
修改dist[i]为dist[i-1] + 1。
b) 约束条件③的判断:
S[i-1]<=S[i] 等效于 S[i-1] – S[mx] <= S[i] – S[mx]。
S[i] – S[mx]就是dist[i],S[i-1] – S[mx]就是dist[i-1],即如果顶点Si-1 到源点的最短路径长度
大于Si 到源点的最短路径,则修改dist[i-1]为dist[i]。


思路:这题确实挺难的,刚学差分约束,还是不太会,这题代码也是看了书上的才理解,只是在约束条件方面自己还不太会,还得多加强练习才行。这题的第一个约束条件根据差分约束的求法自己会写出了,可是第二第三个约束条件往往每题都会有变化,所以还不会求……

#include <iostream>#include <cstdio>#include <fstream>#include <algorithm>#include <cmath>#include <deque>#include <vector>#include <list>#include <queue>#include <string>#include <cstring>#include <map>#define PI acos(-1.0)#define mem(a,b) memset(a,b,sizeof(a))#define sca(a) scanf("%d",&a)#define pri(a) printf("%d\n",a)#define M 50002#define INF 100000001using namespace std;typedef long long ll;int n,dist[M],Max,Min;struct edge{    int u,v,w;}e[M];void init(){    int i;    for(i=0;i<M;i++)        dist[i]=0;    Max=1; Min=INF;}void bellman_ford(){    int i,flag=1;    while(flag)  //没有更新最短路径,则可以结束    {        flag=0;        //Bellman_Ford本身的循环        for(i=0;i<n;i++)        {            if(dist[e[i].v]>dist[e[i].u]+e[i].w)            {                dist[e[i].v]=dist[e[i].u]+e[i].w;                flag=1;            }        }        //根据约束条件s[i]<=s[i-1]+1进一步修改s[i]值        for(i=Min;i<=Max;i++)        {            if(dist[i]>dist[i-1]+1)            {                dist[i]=dist[i-1]+1;                flag=1;            }        }        //根据约束条件s[i-1] <= s[i], 进一步修改s[i-1]值        for(i=Max;i>=Min;i--)        {            if(dist[i-1]>dist[i])            {                dist[i-1]=dist[i];                flag=1;            }        }    }}int main(){    while(~scanf("%d",&n))    {        init();        int i,u,v,w;        for(i=0;i<n;i++)        {            scanf("%d%d%d",&u,&v,&w);            //构造边<v,u-1,-2>            e[i].u=v; e[i].v=u-1; e[i].w=-w;            if(Min>u) Min=u;            if(Max<v) Max=v;        }        bellman_ford();        printf("%d\n",dist[Max]-dist[Min-1]);    }    return 0;}

0 0
原创粉丝点击