NOIP-模拟试题之--分组


2018 NOIP 全套资料下载

【问题描述】

Mr_ he打算把自己棋下的 n 个选手分成若干组。每个选手都提出自己的要求,那就是第 i 个选手要求自己所属的组的人数大等于a[i]人。在满足所有选手的要求的前提下,Mr_he打算最大化组的总数,请你来帮助他!。注意,分组时每个选手属于且仅属于一组。

【输入格式】

第一行一个整数 n, 表示人数。以下 n 行, 每行一个整数表示 a[i]。

【输出格式】

输出队伍总数的最大值。 数据保证有解。

【输入样例】

5
2
1
2
2
3

【输出样例】

2

【数据范围】

对于 20%的数据, n <= 10
对于 40%的数据, n <= 1000
对于 60%的数据, n <= 10000
对于 100%的数据, 1 <= n <= 10^6

————————————————————————————————————————————————————————

可能是出于某种无脑的本能,一开始就想到要贪心去了,实际上最粗暴的贪心很好想就是把需求从大到小排序来直接选人。但是可以被卡掉,比如这组数据:1 1 1 3 4 4 4 4,发现一贪就是3组不巧可以分成4组。
有一种贪心是从小到大排序,然后一直选直到当前满足这组里面所有人的要求为止。出现最后有人分不完的时候就把上一次分组的人合并到这一组里面来,直到分组人数符合要求位为止。

后来还是写的dp,从小到大排序,设f(i)表示以i为结尾的元素中最大分组数量,g(i)表示前i个元素中最大的f值,f(i)=g(i-A[i])+1 ,g(i)=max(g(i-1),f(i))。这样就处理了最开始贪心的不足,防止前面几个人的要求少导致可以分出更多组来的情况出现。

AC代码:

#include< iostream>
#include< cstdio>
#include< cstring>
#include< cstdlib>

#include< algorithm>
#include< cmath>
#include< queue>
#include< set>
#include< map>
#include< vector>
#include< cctype>
using namespace std;
const int maxn=1000005;

int N,A[maxn];
int f[maxn],g[maxn];

void _scanf(int &x)
{
x=0;
char ch=getchar();
while(ch<‘0’||ch>‘9’) ch=getchar();
while(ch>=‘0’&&ch<=‘9’) x=x*10+ch-‘0’,ch=getchar();
}
bool cmp(int x,int y) { return x<y; }
int main()
{
freopen(“team.in”,“r”,stdin);
freopen(“team.out”,“w”,stdout);
_scanf(N);
for(int i=1;i<=N;i++) _scanf(A[i]);
sort(A+1,A+N+1,cmp);
for(int i=1;i<=N;i++)
{
int j=max(0,i-A[i]);
f[i]=g[j]+1;
g[i]=max(f[i],g[i-1]);
}
printf("%d\n",f[N]);
return 0;
}


原文:https://blog.csdn.net/qq_39439314/article/details/78174152

猜你喜欢

转载自blog.csdn.net/tianli315/article/details/84965152