Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 19967 | Accepted: 7559 |
Description
Input
Output
Sample Input
5 3 7 3 8 10 3 6 8 1 1 3 1 10 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 100000001 using 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; }