传送门:
http://acm.hdu.edu.cn/showproblem.php?pid=1384
Intervals
Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 4841 Accepted Submission(s): 1815
Problem 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 endpoints 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
Write a program that:
> reads the number of intervals, their endpoints 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 <= 50 000) - 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 <= 50 000 and 1 <= ci <= bi - ai + 1.
Process to the end of file.
Process to the end of file.
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
Author
1384
Recommend
题目意思:
给出 n 个区间,每个区间有个权值 Ci,最终找出一个最少的数字的集合,使得满足每个区间中至少包含 Ci 个数。
给你几组的a,b,c
从区间a到b(闭区间)选择至少c个数放入集合
要求集合中的数字最少,问你最少多少个数字
分析:
f(a)表示从0到a有f(a)个数放入集合
那么a,b,c根据不等式建立边
f(b)-f(a-1)>=c
这个不等式的意思是:从区间a,b里面选择至少c个数加入集合
隐藏的不等式:0<=f(i)-f(i-1)<=1
变形一下:
f(i)-f(i-1)>=0
f(i-1)-f(i)>=-1
根据这三个不等式建立边
找到区间在最左端:minn
找到区间的最右端:maxx
所以这样建立边的话,跑最短路的时候
起点应该是max,终点是min-1
f(max)-f(min-1)>=x
x就是我们需要的结果
code:
#include <iostream> #include <cstdio> #include<stdio.h> #include<algorithm> #include<cstring> #include<math.h> #include<memory> #include<queue> #include<vector> using namespace std; #define max_v 50010 #define INF 9999999 int tot; int head[max_v]; int vis[max_v]; int dis[max_v]; int minn,maxx; struct node { int u,v,val; int next; }Edge[max_v<<2]; void addEdge(int u,int v,int val) { Edge[tot].u=u; Edge[tot].v=v; Edge[tot].val=val; Edge[tot].next=head[u]; head[u]=tot++; } void spfa() { for(int i=minn-1;i<=maxx;i++) dis[i]=-INF; queue<int> q; dis[maxx]=0; vis[maxx]=1; q.push(maxx); while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; for(int i=head[u];i!=-1;i=Edge[i].next) { int v=Edge[i].v; if(dis[v]<dis[u]+Edge[i].val) { dis[v]=dis[u]+Edge[i].val; if(!vis[v]) { vis[v]=1; q.push(v); } } } } printf("%d ",dis[minn-1]); return ; } int main() { int n,a,b,c; while(~scanf("%d",&n)) { tot=0; memset(head,-1,sizeof(head)); memset(vis,0,sizeof(vis)); maxx=0; minn=INF; for(int i=0;i<n;i++) { scanf("%d %d %d",&a,&b,&c); a++; b++; minn=min(minn,a); maxx=max(maxx,b); addEdge(b,a-1,c); } for(int i=minn;i<=maxx;i++) { addEdge(i,i-1,0); addEdge(i-1,i,-1); } spfa(); } return 0; }
今天学差分约束的时候又遇到了这个题,跑最长路初始化的时候搞错了,应该是dis[i]=-INF。。。。,卡了好一会
题目意思:
从一系列区间[a,b]中每个至少取ci个数构成集合s,问你集合s至少需要多少个数
区间约束问题,差分约束解决
从一系列区间[a,b]中每个至少取ci个数构成集合s,问你集合s至少需要多少个数
区间约束问题,差分约束解决
分析:
f(x):[0,x]区间内取f(x)个数
f(x):[0,x]区间内取f(x)个数
则区间[a,b]内至少取c个数可以变形为:f(b)-f(a-1)>=c
隐藏关系:1>=f(i)-f(i-1)>=0,变形一下:
f(i)-f(i-1)>=0
f(i-1)-f(i)>=-1
maxx:所有区间的最大值
minx:所有区间的最小值
隐藏关系:1>=f(i)-f(i-1)>=0,变形一下:
f(i)-f(i-1)>=0
f(i-1)-f(i)>=-1
maxx:所有区间的最大值
minx:所有区间的最小值
i属于[minx,maxx]
总结一下得到这样三个关系:
f(b)-f(a-1)>=c
f(i)-f(i-1)>=0 i属于[minx,maxx]
f(i-1)-f(i)>=-1 i属于[minx,maxx]
f(b)-f(a-1)>=c
f(i)-f(i-1)>=0 i属于[minx,maxx]
f(i-1)-f(i)>=-1 i属于[minx,maxx]
这三个表达式的形式都是一样的,xi-xj>=c
按照j->i建边,权值为c
所以:
(a-1)->b 建边 权值c
(i-1)->i 建边 权值0
i->(i-1) 建边 权值-1
按照j->i建边,权值为c
所以:
(a-1)->b 建边 权值c
(i-1)->i 建边 权值0
i->(i-1) 建边 权值-1
我们要求的东西ans可以变形为:f(maxx)-f(minx-1)>=ans
>=是最小值,所以是最长路
所以是问你从minx-1到maxx的最长路
建图完毕之后spfa跑一遍最长路,不能用dj,因为存在负权边
>=是最小值,所以是最长路
所以是问你从minx-1到maxx的最长路
建图完毕之后spfa跑一遍最长路,不能用dj,因为存在负权边
code:
#include<stdio.h> #include<iostream> #include<math.h> #include<string.h> #include<set> #include<map> #include<list> #include<math.h> #include<queue> #include<algorithm> using namespace std; typedef long long LL; #define INF 9999999999 #define me(a,x) memset(a,x,sizeof(a)) int mon1[13]= {0,31,28,31,30,31,30,31,31,30,31,30,31}; int mon2[13]= {0,31,29,31,30,31,30,31,31,30,31,30,31}; int dir[4][2]= {{0,1},{0,-1},{1,0},{-1,0}}; int getval() { int ret(0); char c; while((c=getchar())==' '||c==' '||c==' '); ret=c-'0'; while((c=getchar())!=' '&&c!=' '&&c!=' ') ret=ret*10+c-'0'; return ret; } void out(int a) { if(a>9) out(a/10); putchar(a%10+'0'); } #define max_v 50005 int dis[max_v]; int vis[max_v]; struct node { int v,w; node(int vv=0,int ww=0):v(vv),w(ww){} }; vector<node> G[max_v]; int n,m; void init() { for(int i=0;i<max_v;i++) G[i].clear(); for(int i=0;i<max_v;i++) { dis[i]=-INF; vis[i]=0; } } void spfa(int s) { queue<int> q; q.push(s); vis[s]=1; dis[s]=0; while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=0; for(int j=0;j<G[u].size();j++) { int v=G[u][j].v; int w=G[u][j].w; if(dis[v]<dis[u]+w)//最长路 { dis[v]=dis[u]+w; if(vis[v]==0) { vis[v]=1; q.push(v); } } } } } int f(int u,int v) { for(int j=0;j<G[u].size();j++) { if(G[u][j].v==v) return 0; } return 1; } int main() { int a; while(~scanf("%d",&a)) { int x,y,w; init(); int maxx=-INF,minx=INF; for(int i=1;i<=a;i++) { scanf("%d %d %d",&x,&y,&w); x++,y++;//防止减1的时候出现负数 maxx=max(maxx,y); minx=min(minx,x); if(f(x-1,y))//预防重边 G[x-1].push_back(node(y,w)); } for(int i=minx;i<=maxx;i++) { if(f(i-1,i))//预防重边 G[i-1].push_back(node(i,0)); if(f(i,i-1))//预防重边 G[i].push_back(node(i-1,-1)); } spfa(minx-1); printf("%d ",dis[maxx]); } return 0; } /* 题目意思: 从一系列区间[a,b]中每个至少取ci个数构成集合s,问你集合s至少需要多少个数 区间约束问题,差分约束解决 分析: f(x):[0,x]区间内取f(x)个数 则区间[a,b]内至少取c个数可以变形为:f(b)-f(a-1)>=c 隐藏关系:1>=f(i)-f(i-1)>=0,变形一下: f(i)-f(i-1)>=0 f(i-1)-f(i)>=-1 maxx:所有区间的最大值 minx:所有区间的最小值 i属于[minx,maxx] 总结一下得到这样三个关系: f(b)-f(a-1)>=c f(i)-f(i-1)>=0 i属于[minx,maxx] f(i-1)-f(i)>=-1 i属于[minx,maxx] 这三个表达式的形式都是一样的,xi-xj>=c 按照j->i建边,权值为c 所以: (a-1)->b 建边 权值c (i-1)->i 建边 权值0 i->(i-1) 建边 权值-1 我们要求的东西ans可以变形为:f(maxx)-f(minx-1)>=ans >=是最小值,所以是最长路 所以是问你从minx-1到maxx的最长路 建图完毕之后spfa跑一遍最长路,不能用dj,因为存在负权边 */