zoj 1508 && poj 1201 Intervals

来源:互联网 发布:基础设施网络建设 编辑:程序博客网 时间:2024/05/21 19:42

题意:给定n个整数的闭区间和n个整数c1,c2,...,cn。编程实现以下三点。

⑴以标准输入方式读入闭区间的个数,每个区间的端点和整数c1,c2,...,cn。

⑵求一个最小的整数集合Z,满足Z在[ai,bi]这个闭区间的个数不小于ci个。

⑶以标准输出方式输出答案,输出Z的个数。


分析:该题目可以建模成一个差分约束系统。以样例输入为例进行分析。

⑴Z集合在范围[ai,bi]的整数个数即,s[bi] - s[ai]至少为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,区间左端点的最小值为mn,那么最终要求的是s[mx] - s[mn-1]的最小值,即s[mx] - s[mn-1] >= M中的M,转换成s[mn-1] - s[mx] <= -M,即要求源点s[mx]到s[mn]的最短路径。

因为最后两个约束条件很普遍,所以我们不必将边添加到邻接表当中,在程序中添加两个判断即可。

以上参考自:《图论算法理论、实现及应用》 ----北京大学出版社


spfa代码

#include <iostream>#include <algorithm>#include <cstdio>#include <queue>using namespace std;const int inf = 1000000000;const int maxn = 50005;struct edge{int v,w;int next;edge(){}};int n;int dist[maxn];bool inq[maxn];queue<int> q;int list[maxn];edge a[maxn];int mx,mn;bool input(){if(scanf("%d",&n) == EOF) return false;int u,v,w;for(int i = 0; i < maxn; i++) list[i] = -1;mx = -inf;mn = inf;for(int i = 0; i < n; i++){scanf("%d%d%d",&v,&u,&w);mn = min(mn,v);mx = max(mx,u);a[i].v = v-1;a[i].w = -w;a[i].next = list[u];list[u] = i;}return true;}void relax(int u, int v, int w){if(dist[u] + w < dist[v]){dist[v] = dist[u] + w;if(!inq[v]){q.push(v); inq[v] = true;}}}void spfa(int s){for(int i = mn-1; i <= mx; i++){dist[i] = inf;inq[i] = false;}dist[s] = 0;q.push(s);while(!q.empty()){int u = q.front(); q.pop(); inq[u] = false;//s[i] - s[i-1] <= 1if(u+1 < maxn)relax(u,u+1,1);//s[i] - s[i-1] >= 0if(u-1 >= 0)relax(u,u-1,0);for(int p = list[u]; p != -1; p = a[p].next){relax(u,a[p].v,a[p].w);}}}void solve(){spfa(mx);printf("%d\n",-dist[mn-1]);}int main(){while(input()){solve();}return 0;}



0 0
原创粉丝点击