贪心之种树(区间选点问题)

       描述

一条街的一边有几座房子。因为环保原因居民想要在路边种些树。路边的地区被分割成块,并被编号为1..n。每个块大小为一个单位尺寸并最多可种一棵树。每个居民想在门前种些树并指定了三个号码b,e,t。这三个数表示该居民想在b和e之间最少种t棵树。当然,b<=e,居民必须保证在指定地区不能种多于地区被分割成块数的树,即要求t<=e-b+1。允许居民想种树的各自区域可以交叉。出于资金短缺的原因,环保部门请你求出能够满足所有居民的要求,需要种树的最少数量。

输入
共n+1行
第1行:输入一个n,表示有n户居民提出要求要在门前种树(1≤n≤100)
后n行:每行输入3个数bi、ei和ti,用空格隔开,分别表示第i户居民想在门前的起点bi到终点ei(包括端点),想种ti颗树(1≤bi≤ei≤100)
输出
满足n户居民的最少种树量
样例输入
3
1 3 2
2 6 3
7 10 1
样例输出
4
提示
贪心(区间问题)
解题思路:
首先题目要求是居民想种的树的各自区域可以相交,并且请你求出能够满足所有居民的要求,需要种树的最少数量,所以就可以想到尽量在相交的部分种树可以使种树的数量最少。由于每位居民与上一位居民的相交处位于上一位居民的尾部,所以我们可以考虑从尾部开始种树。排序的过程是先按照每户居民的结束位置从小到大排列,如果结束位置相等,则按照开始位置从大到小排列。

    样例程序:

#include<iostream>
#include<algorithm>
using namespace std;
struct home//结构体中包括b,e,t
{
	int b,e,t;
}c[105];
int flag[10005]={0},sum;//flag用来表示该位置是否有树
int gs(int x,int y)//种树函数,从尾部y开始倒着种树,种x棵
{
	while(y)
	{
		flag[x]=1;
		x--;y--;
	}
	return 0;
}
int ss(int x,int y)//数树函数,用来计算x到y之间有多少棵树
{
	sum=0;
	for(int i=x;i<=y;i++)
		if(flag[i]==1)
			sum++;
	return sum;
}
int cmp(home x,home y)//排序函数
{
	if(x.e<y.e) return 1;//先按照结束位置从小到大排列
	else if(x.e==y.e&&x.b>y.b) return 1;//结束位置相同,把开始位置大的放在前面
		else return 0;
}
int main()
{
	int n,i,tot=0,tmp;//tot表示所要种的树的总数
	cin>>n;
	for(i=1;i<=n;i++)
		cin>>c[i].b>>c[i].e>>c[i].t;
	sort(c+1,c+1+n,cmp);//进行排序
	gs(c[1].e,c[1].t);//为第一户居民种树
	tot+=c[1].t; 
	for(i=2;i<=n;i++)
	{
		if(c[i].b<=c[i-1].e)//如果这个居民的种树的开始位置小于上一个居民的结束位置,有相交区域
		{
			tmp=ss(c[i].b,c[i-1].e);//计算出相交位置有多少棵树(tmp)
			if(tmp>=c[i].t)//如果大于该居民所要种植的树,则不需要在种树
				continue;
			else
				gs(c[i].e,c[i].t-tmp);//否则再从该居民的尾部开始种树,数量为c[i].t-tmp
				tot+=c[i].t-tmp;//改变tot的值
		}
		else//如果没有相交的区域
		{
			gs(c[i].e,c[i].t);//从该居民的结束位置倒着种树
			tot+=c[i].t;
			
		}
	}
	cout<<tot;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值