练习题 旅行(重庆一中高2018级信息学竞赛测验4) 解题报告

时间:2023-02-24 08:26:38
【问题描述】  
  
  Mr_H旗下的 n 个OIer坐船外出旅行! 


  但是他们只有一艘船,虽然船能装下全部的Oier,但太拥挤将会影响众OIer的心情,所以Mr_H决定选择一部分Oier去。我们假设,每个人单独坐船的快乐程度是Ci,而船上每多一个人,他的快乐程度会减去Di。 


  现在你的任务是帮助Mr_H计算,选择那些人,才能使船上所有人的快乐程度之和达到最大。 
 
    
 【输入格式】  
  
  第1行是一个整数n,表示OIer的人数;
  第2行有n个整数,第i个整数表示第i个人人单独坐船的快乐程度Ci(1<=Ci<=10000);
  第3行有n个整数,第i个整数表示每多1人,第i个人快乐程度的下降值Di(1<=Di<=10)。


 
    
 【输出格式】  
   
  第1行一个整数,是最大的快乐程度之和;
  第2行一个整数,是最大的快乐程度之和所对应的汽艇上的人数(若有多种方案,则输出人数最多的)。


 
    
 【输入样例】   
   
6
10 10 10 10 10 9
2 2 2 2 2 3 
 
    
 【输出样例】  
   
18

 
    
 【样例解释】  
   
  前3个人去坐汽艇可使快乐程度之和达到最大,每个人的快乐程度均为10-2*2=6,总和是18。
 
    
 【数据范围】  
   
对于30%的数据,n<=20;

对于100%的数据,n<=1000。


【来源】 

  原创命题


做题思路(正解):这道题的主要算法为贪心算法,因为我们不知道最终汽艇上有多少人,所以先枚举汽艇上的人数k,按每个人此时的快乐程度由大到小排序,选择前k个快乐程度最大的人(贪心策略),然后计算出的快乐程度之和取最大值,即为所求。需要注意的是,如果有多种方案,要输出人数最多的。


#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=1005;
int N,k;
struct data
{
	int c,d;
};
data a[maxn];
bool cmp(data aa,data bb)
{
	return aa.c-(k-1)*aa.d>bb.c-(k-1)*bb.d;  //注意,计算快乐程度时,人数要减去自己
}
int main()
{
	freopen("travel.in","r",stdin);
	freopen("travel.out","w",stdout);
	scanf("%d",&N);
	for(int i=1;i<=N;i++)
	scanf("%d",&a[i].c);
	for(int i=1;i<=N;i++)
	scanf("%d",&a[i].d);
	int ans=0,cnt=0;
	for(k=1;k<=N;k++)  //依次枚举有k个人在汽艇上,求出此时最大的快乐程度之和 
	{
		sort(a+1,a+1+N,cmp);  //按此时每个人的快乐程度由大到小排序 
		int sum=0;
		for(int i=1;i<=k;i++)
		sum+=a[i].c-(k-1)*a[i].d;
		if(sum>ans || (sum==ans && cnt<k))  //如果有多种方案,输出人数最多的 
		{
			ans=sum;
			cnt=k;
		}
	}
	printf("%d\n",ans);
	printf("%d\n",cnt);
	return 0;
}

考后反思:对于某些未知变量且这些变量范围较小时,可以枚举,同时,找准贪心策略是非常重要的。