《黑书》uva10148(区间选点问题)贪心

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&category=13&problem=1089&mosmsg=Submission+received+with+ID+11785491

题意:有n段区间,每段区间至少要有k个广告牌,要求你在这些区间放置广告牌,但是广告牌的数量要是最少的,而且将其位置输出来。

思路:经典贪心,区间选点问题。《算法入门经典》P154。

假设每个区间是【ai, bi】, 那么先按照每个区间的bi从小到大排序。
下图是排好序的四个区间。为了使得广告位数量最少,那么就要让这些广告位尽量的处在越多人重复经过的地方越好。
观察下图可以看出,为了让重叠部分越多,那么每个区间选点时,就要让这些点尽可能的往改区间的右边靠。
在对每个区间选点时,先查看该区间之前已经被选好几个点了,如果不够的话再补上。
代码:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct ss
{
	int x,y;
}s[1005];
int vist[20005];
int cmp(const ss a,const ss b)
{
	if(a.y<b.y)
	return 1;
	else 
	return 0;
}
int main()
{
	int text;
	scanf("%d",&text);
	while(text--)
	{
		int n,k;
		scanf("%d%d",&k,&n);
		int maxx=0;
		for(int i=0;i<n;i++)
		{
			scanf("%d%d",&s[i].x,&s[i].y);
			if(s[i].x>s[i].y)
			{
				int tmp=s[i].x;
				s[i].x=s[i].y;
				s[i].y=tmp;
			}
			s[i].x+=10000;
			s[i].y+=10000;
			if(maxx<s[i].y)
			maxx=s[i].y;
		}
		memset(vist,0,sizeof(vist));
		sort(s,s+n,cmp);
		int sum=0;
		for(int i=0;i<n;i++)
		{
			int flag=0;
			for(int j=s[i].x;j<=s[i].y;j++)
			if(vist[j])
			flag++;
			if(flag>=k)
			continue;
			else
			{
				for(int j=s[i].y;j>=s[i].x&&flag<k;j--)
				if(!vist[j])
				{
					vist[j]=1;
					flag++;
					sum++;
				}
			}
		}
		printf("%d\n",sum);
		for(int i=0;i<=maxx;i++)
		if(vist[i])
		printf("%d\n",i-10000);
		if(text)
		printf("\n");
	}
	return 0;
}

 

posted @ 2013-05-19 20:20  紫忆  阅读(1479)  评论(0编辑  收藏  举报