BZOJ3661Hungry Rabbit 贪心

Posted CQzhangyu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ3661Hungry Rabbit 贪心相关的知识,希望对你有一定的参考价值。

【BZOJ3661】Hungry Rabbit

Description

可怕的洪水在夏天不期而至,兔子王国遭遇了前所未有的饥荒,它们不得不去外面的森林里寻找食物。
为了简化起见,我们假设兔子王国中有n只兔子,编号为1n。在救济粮到来之前的m天中,每天恰好有k只兔子需要去森林里寻找粮食。森林里居住着可怕的大灰狼,所幸兔子已经摸清了大灰狼捕食习惯,即狼们在每一天只会捕食特定编号的兔子。为了安全起见,兔子们需要保证每次出去觅食的k只兔子都不会被狼捕食。由于每天出去捕食的兔子都不尽相同,它们为每一天定义了一个生疏度pi,即第i天出来寻找食物,但是第i1天却没有出来觅食的兔子个数。规定第1天的生疏度为0.现在兔子们希望在保证安全的前提下,每天的生疏度不能超过L,请为兔子们构造一个合法的方案。

Input

第一行包括四个整数n,m,k和L.
接下来n行,每行一个长度为m的01串。其中第i行第j个字符若为0,则表示狼在第j天会捕食编号为i的兔子,为1则表示不捕食。

Output

m行,每行k个1-n之间互不相同的整数,代表这一天出去寻找食物的兔子编号。如果没有合法方案,则输出一行1即可。

Sample Input

5 4 3 1
1001
1101
1111
1110
0111

Sample Output

2 3 4
2 3 4
3 4 5
2 3 5

HINT

对于 100% 的测试数据,1 <= n;m <= 800; 1 <= k <= n; 1 <= l <= k

题解:一开始以为是个网络流,结果正解居然是贪心。。。

我们先预处理出len[i][j]代表每一天的每只兔子最多能往后连续出去多少天,那么每天我们一定是贪心的选择len最大的出去。具体怎么做呢?我们已知第i-1天出去的兔子集合是q,剩下的兔子的集合是p,那么将p按len从大到小排序,将p按len从小到大排序,然后交换p和q的前L个(如果可以的话)。最后判断一下是否可行即可。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
int n,m,now,K,L;
char str[810][810];
int f[810][810],len[810][810],r1[810],r2[810],vis[810],ans[810][810];
inline int rd()
{
	int ret=0,f=1;	char gc=getchar();
	while(gc<‘0‘||gc>‘9‘)	{if(gc==‘-‘)f=-f;	gc=getchar();}
	while(gc>=‘0‘&&gc<=‘9‘)	ret=ret*10+gc-‘0‘,gc=getchar();
	return ret*f;
}
bool cmp(int a,int b)
{
	return len[now][a]>len[now][b];
}
int main()
{
	scanf("%d%d%d%d",&n,&m,&K,&L);
	int i,j,*p=r1,*q=r2,tp;
	for(i=1;i<=n;i++)	scanf("%s",str[i]+1);
	for(j=m;j;j--)	for(i=1;i<=n;i++)	len[j][i]=(str[i][j]==‘0‘)?0:(len[j+1][i]+1);
	for(j=1;j<=m;j++)
	{
		now=j,tp=0;
		for(i=1;i<=n;i++)	if(len[j][i]&&!vis[i])	p[++tp]=i;
		sort(p+1,p+tp+1,cmp);
		if(j!=1)
		{
			sort(q+1,q+K+1,cmp);
			for(i=1;i<=L&&i<=tp;i++)	if(len[j][p[i]]>len[j][q[K-i+1]])	swap(p[i],q[K-i+1]);
			if(i!=K+1&&!len[j][q[K-i+1]])
			{
				printf("1");
				return 0;
			}
			memset(vis,0,sizeof(vis));
			swap(p,q);
		}
		else
		{
			if(tp<K)
			{
				printf("1");
				return 0;
			}
		}
		for(i=1;i<=K;i++)	vis[p[i]]=1,ans[j][i]=p[i];
		swap(p,q);
	}
	for(j=1;j<=m;j++)	for(i=1;i<=K;i++)	printf("%d%c",ans[j][i],i==K?‘\n‘:‘ ‘);
	return 0;
}/*
4 4 3 1
1110
1101
1011
0111
*/

以上是关于BZOJ3661Hungry Rabbit 贪心的主要内容,如果未能解决你的问题,请参考以下文章

[贪心] aw3661. 重置数列(贪心+枚举+细心+aw周赛003_2)

bzoj 1669: [Usaco2006 Oct]Hungry Cows饥饿的奶牛dp+树状数组+hash

BZOJ4660Crazy Rabbit 结论+DP

bzoj 1034 [ZJOI2008]泡泡堂BNB(贪心)

bzoj 1029: [JSOI2007]建筑抢修 贪心

bzoj 1664 (贪心)