P4447 [AHOI2018初中组]分组 题解

P4447 [AHOI2018初中组]分组 题解

题目描述

小可可的学校信息组总共有n 个队员,每个人都有一个实力值a[i]a[i]。现在,一年一度的编程大赛就要到了,小可可的学校获得了若干个参赛名额,教练决定把学校信息组的nn 个队员分成若干个小组去参加这场比赛。

但是每个队员都不会愿意与实力跟自己过于悬殊的队员组队,于是要求分成的每个小组的队员实力值连续,同时,一个队不需要两个实力相同的选手。举个例子:[1, 2, 3, 4, 5][1,2,3,4,5]是合法的分组方案,因为实力值连续;[1, 2, 3, 5][1,2,3,5]不是合法的分组方案,因为实力值不连续;[0, 1, 1, 2][0,1,1,2]同样不是合法的分组方案,因为出现了两个实力值为1 的选手。

如果有小组内人数太少,就会因为时间不够而无法获得高分,于是小可可想让你给出一个合法的分组方案,满足所有人都恰好分到一个小组,使得人数最少的组人数最多,输出人数最少的组人数的最大值。

注意:实力值可能是负数,分组的数量没有限制。

输入格式

输入有两行:

第一行一个正整数n,表示队员数量。
第二行有n 个整数,第i 个整数a[i]表示第i 个队员的实力。

输出格式

输出一行,包括一个正整数,表示人数最少的组的人数最大值。

输入输出样例

输入 

7
4 5 2 3 -4 -3 -5

输出

3

题解

咋一看非常简单,直接排序,然后找出连续段的个数并记录最小段的人数。提交发现wa也一片。

解决贪心问题的基本思路

1.建立数学模型来描述问题。

2.把求解的问题分成若干个子问题。

3.对每一子问题求解,得到子问题的局部最优解。

4.把子问题的局部最优解合成原来问题的一个解。

正解:

把每一个组看成一个队列。我们只要关心的是队尾每次插入的元素是什么就行。将n个数排序,从头到尾扫一遍,每次扫到一个数,就看一看现有的组(队列)中有没有末尾是该数-1的,有就插入进去,该组数量+1。直到扫完,输出最小组数的长度。每次选队列时,为了增高平均水平当然是加给最短的那个,如果没有符合要求的,新开一个队列。

#include<bits/stdc++.h> 
using namespace std;
int a[100100];
int lastt[100100],lengthh[100100];
int main(){
	int n;
	cin>>n;
	for(int i = 1;i<=n;i++) cin>>a[i];
	sort(a+1,a+1+n);
	int count = 0;
	for(int i = 1;i<=n;i++){//遍历所有队员
		bool flag = 0;
		int reg = 0;
		int maxn = 1000100;
		for(int j = 1;j<=count;j++)//一组一组遍历所有已经分的组 
			if(lastt[j]==a[i]-1 && lengthh[j]<maxn)//找到可以放第i个队员的组(多组满足时,选人员最少组) 
			{
				maxn = lengthh[j];//记录该组人数
				reg = j;//记录该组序号
				flag = 1;//找到标记 
			}
		if(flag)//如果找到
		{
			lastt[reg] = a[i];//该组最后一个队员变为a[i]
			lengthh[reg]++;//该组人数增加1
		}
		else//如果没有找到,建新的组 
		{
			lastt[++count] = a[i];
			lengthh[count] = 1; 
		}
	}
	int ans = 1000100;
	for(int i = 1;i<=count;i++)
		if(lengthh[i]<ans) ans = lengthh[i];
	cout<<ans;
	return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值