1398. 烤饼干

1398. 烤饼干

题目描述
NOIP烤饼干时两面都要烤,而且一次可以烤R(1<=R<=10)行C(1<=C<=10000)列个饼干,当一面烤到规定时间时,机器会把整个翻过来以接着烤另一面。
有一天,正当机器准备翻饼干时发生了地震,有一些饼干被翻了过来,有一些没有。幸运的是,地震过后你可以手工操作,一次可以同时翻若干行或者若干列,但不能单独翻某一个饼干。
写一个程序计算通过翻转使得最终翻过来的饼干的数量得最大值。 例如下图是地震之后的情况,黑点表示未翻转,白点表示已经翻转:
在这里插入图片描述
翻转第一行后得到:
在这里插入图片描述
接着翻转第1列和第5列得到下图:
在这里插入图片描述
这样可以使得9个饼干翻转过来。

输入
第1行: 两个整数R和C(1<=R<=10,1<=C<=10000);

接下来R行,每行C个空格隔开的数,其中aij=1表示未被翻转,0表示已经翻转。

输出
输出一个整数表示通过翻转行列操作最多被翻转的饼干数量。

样例输入
样例输入1:

2 5
0 1 0 1 0
1 0 0 0 1

样例输入2:

3 6
1 0 0 0 1 0
1 1 1 0 1 0
1 0 1 1 0 1

样例输出
样例输出1:

9

样例输出2:

15

方法一(dfs):
因为最多只有十行,所以行的变化只有210=1024种。我们有深搜去模拟每一种行的变化。
对于每一列,我们使用贪心,只有翻后已翻过的干更多,我们才翻。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
using namespace std;
const int MAX=2147483647;
const int N=1e6;
int n,m,a[11][10010],ans; 
void dfs(int step)
{
	if(step>n)
	{
		int temp=0;
		for(int j=1;j<=m;j++)
		{
			int t=0;
			for(int i=1;i<=n;i++)
				t+=a[i][j];	
			temp+=max(t,n-t);	
		}
		ans=max(ans,temp);
		return ;
	}
	dfs(step+1);
	for(int i=1;i<=m;i++) a[step][i]^=1;
	dfs(step+1);
	for(int i=1;i<=m;i++) a[step][i]^=1;
}
int main()
{
	//fre();
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++)
		scanf("%d",&a[i][j]);
	dfs(1);
	printf("%d",ans);
	return 0;
}

方法二(模拟):
我们用两层循环来进行模拟,外循环来枚举行的所有变化(1<<n种),内循环统计该种变化下能翻的最多饼干数,跟上面贪心一致,但用了状压dp的思想和一些套路。

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
using namespace std;
const int MAX=2147483647;
const int N=1e6;
int data,n,m,f[N];
long long tot,ans;
int sum(int x)
{
	int i=0;
	for(i=0;x;i++) x&=(x-1);
	return i;
}
int main()
{
	//fre();
	cin>>n>>m;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		{
			cin>>data;
			f[j]=(f[j]<<1)|data;
		}
	for(int i=0;i<(1<<n);i++)
	{
		tot=0;
		for(int j=1;j<=m;j++)
		{
			int t=sum(i^f[j]);
			tot+=max(t,n-t);
		}
		ans=max(ans,tot);
	}
	cout<<ans;			
	return 0;
}

方法三(状压dp):

#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<string>
#include<algorithm>
#include<vector>
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout);
using namespace std;
const int MAX=2147483647;
const int N=1e6;
int n,m,data,f[2010],ans,a[10010];
int main()
{
	//fre();
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++)
		scanf("%d",&data),a[j]=(a[j]<<1)|data; 
	for(int i=1;i<=m;i++)
		for(int j=0;j<(1<<n);j++)
		{
			int tot=0;
			for(int k=0;k<n;k++)
				if(1<<k&j)	{if(1<<k&a[i]) tot++;}  
				//i列第k行要翻,且第k行的饼干未翻。 
				else if(!(1<<k&a[i])) tot++;
				//i列第k行不翻,且第k行的饼干已翻。 
			f[j]+=max(tot,n-tot);
		}
	for(int i=0;i<(1<<n);i++) ans=max(ans,f[i]);
	printf("%d",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/bigwinner888/article/details/106740027
今日推荐