描述
-
一条街的一边有几座房子。因为环保原因居民想要在路边种些树。路边的地区被分割成块,并被编号为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;
}