POJ 1201 差分约束(链式前向星

Intervals
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 26192 Accepted: 10015

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

5
3 7 3
8 10 3
6 8 1
1 3 1
10 11 1

Sample Output

6



很有收获的一道题,感觉对差分约束的理解更深了一点。

题意:平面上有n个区间,第i个区间的左端点为ai,右端点为bi。然后求一个最短长度的集合z,使该集合在每一个区间[ai,bi],都至少有ci个点在区间中。求z集合的长度。

思路:一开始的思路是贪心,很明显可以将区间按右端点排序,然后每个区间就从最右边开始选m个点(m为ci - 该区间已经被选的点的个数,m<=0时,则该区间可以不选。)。优化可以用一个线段树或树状数组维护。


但既然是在学差分约束,当然还是用差分约束系统来做。


开始一直没有思路,因为我以前遇见的都是求最大值,最小值并不知道怎么入手。

然后看了网上的一个博客,才知道:

求最大值: 方程变形为:  a - b <= c ,b->a,权边为c。 求最短路
求最小值:  方程变形为: b - a >= -c,a->b,权边为-c。求最长路


然后还有一个关键点在于,如果要得到正确答案,必须保证相邻点连通。

因为:
 0 <=  a[i+1] - a[i]  <= 1

然后两点之间加两条边即可。




#include <iostream>
#include <cstdio>
#include <cstdlib>
#include<cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <cctype>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;

const int maxn = 50000 + 100;
const int INF = 1e8;
struct P{
	int v,w,next;
}G[maxn*20];
int head[maxn],out[maxn],dis[maxn],vis[maxn];
int n,tot;

void init(void){
	tot = 0;
	memset(head,-1,sizeof(head));
}

void add(int u,int v,int w){
	G[tot].v = v;
	G[tot].w = w;
	G[tot].next = head[u];
	head[u] = tot++;
}

int spfa(int st,int ed){
	queue<int> que;
	for(int i=0 ;i<=ed ;i++){
		dis[i] = -INF;
		vis[i] = 0;
		out[i] = 0;
	}
	dis[st] = 0;
	vis[st] = 1;
	que.push(st);
	while(que.size()){
		int u = que.front();
		que.pop();
		vis[u] = 0;
		for(int i=head[u] ;i!=-1 ;i=G[i].next){
			int v = G[i].v,w = G[i].w;
			if(dis[u] + w > dis[v]){
				dis[v] = dis[u] + w;
				if(!vis[v]){
					vis[v] = 1;
					que.push(v);
				}
			}	
		}	
	}
	return dis[ed];
}

void solve(int u,int v){
	printf("%d\n",spfa(u,v));
}

int main(){
	while(scanf("%d",&n) != EOF){
		init();	
		int a,b,c;
		int u=maxn,v=0;
		while(n--){
			scanf("%d%d%d",&a,&b,&c);
			add(a,b+1,c);
			u = min(u,a);
			v = max(v,b+1);
		}
		for(int i=0 ;i<=v ;i++){
			add(i+1,i,-1);
			add(i,i+1,0);
		}
		solve(u,v);
	}
	return 0;
} 







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值