ZOJ1508 (差分约束)

Intervals

Time Limit: 10 Seconds       Memory Limit: 32768 KB

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.


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.


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



【题解】通过观察发现,这道题目就是再求每个位置上是0 还是 1 。

      而题目的信息点之间具有一些不等式:

           设数组s[],表示第i 个数以前包括i 有多少个1;

得 s[ i ]-s[i-1]>=0;s[i]>=s[i-1]+0;

  s[i-1]-s[i]>=-1; s[i-1]>=s[i]-1;

s[ b[ i ] ]-s[ a[ i ] ]>=c[ i ] ---> s[ b[ i ] ]>=s[ a[ i ] ]+c[ i ];  所以这就是差分约束,这些不等式就是spfa 的比较方式,也就是说做一遍spfa 就可以让 s[] 数组的值做这些 “松弛” 操作,最后得到的 s[ n ] 就是所求值。



下面附上代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>

#define maxn 51000
#define maxm 200000
#define inf 2147483641

int tot,edge[maxm],s[maxn],twice[maxn],to[maxm],next[maxm],d[maxn],f[maxn*200],n;

inline void add(int x,int y,int z){
       edge[++tot]=z;to[tot]=y;next[tot]=s[x];s[x]=tot;
}
inline void spfa(int x)
{
	   memset(d,0x7f,sizeof(d));
       memset(twice,0,sizeof(twice));       
       int head=1,tail=1;d[x]=0;
       f[1]=x;twice[x]=1;
       
       while(head<=tail){
       		int id=f[head++];
       		twice[id]=0;
			for(int i=s[id];i;i=next[i])
			 if(d[to[i]]>d[id]+edge[i]){
					d[to[i]]=d[id]+edge[i];
					if(!twice[to[i]]){
						twice[to[i]]=1;
						f[++tail]=to[i];
					}
			}
       }
}
int main()
{
	while(scanf("%d",&n)!=EOF){
		int maxx=0,minx=50005;tot=0;
    	memset(s,0,sizeof(s));
    	for(int i=1,a,b,c;i<=n;i++){
     	       scanf("%d%d%d",&a,&b,&c);
     	       a++;b++;
     	       if(a<minx)minx=a;
     	       if(b>maxx)maxx=b;
    	 	   add(a-1,b,-c);
    	}
    	int v0=minx-1;add(v0,minx,0);
    	for(int i=minx;i<=maxx;i++){
       	     add(i,i+1,0);
       	     add(i,i-1,1);
    	}
    	spfa(v0);
    	printf("%d\n",-d[maxx+1]);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值