Fliptile POJ - 3279

http://poj.org/problem?id=3279

状态压缩+bfs

先说说思路吧:一个点的翻转对其上下有影响,故i+1行翻转结束后,必须确保i-th全部为零,故采取递推的方式,第一行的翻转状态任意,地推到第二行,第二行的操作可以被唯一确定因为该行的操作必须保证上一行全部为零,以此类推到末行,末行的操作保证上一行为零且自己也为零。

细节处理:以下bfs代码如果改成传统的bfs形式(即层层调用函数会超时),开始一直超时改成循环递推才过的。对自己特别强调下各个位运算的优先度,其他的一些见代码中的注释。

ac code:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<climits>
#define   handle(row,i) temp[t][row]^=i,temp[t][row]^=i<<1,temp[t][row]^=i>>1
//  通过位运算实现 翻转操作
using namespace std;
const int M=INT_MAX/2;
int n,m;
int temp[2][17],tt[17],re[17];
int record[1<<15],num;
void init()
{
	int t;
	memset(temp,0,sizeof(temp));
	for(int i=1;i<=n;++i)
	{
		for(int j=1;j<=m;++j)
		{
		    scanf("%d",&t);
		    if(t==1)temp[0][i]+=1<<(m-j);
                    //将地图转换成二进制数便于位操作
		}
	}
}
void pre()
{
	int t;
	memset(record,0,sizeof(record));
	for(int i=0;i<1<<15;++i)
	{
		for(int j=0;j<15;++j)
		{
			t=1<<j;
			if((i&t))record[i]++;//记下对一整行某种操作的代价
		}
	}
}
bool cmp()
{
	for(int i=1;i<=n;++i)
    {
    	if(tt[i]<re[i])return true;
    	else if(tt[i]>re[i])return false;//保证题目要求的字典序
	}
}
int main()
{
	pre();
	while(cin>>n>>m)
	{
		init();
		num=1<<m;
		int t=1,hand,sum,ans;
		memset(re,0,sizeof(re));
		memset(tt,0,sizeof(tt));
		ans=M;
		for(int i=0;i<num;++i)
		{
			sum=0;
			for(int j=1;j<=n;++j)   
			temp[t][j]=temp[!t][j];
			handle(1,i);
			if(temp[t][1]&num)temp[t][1]^=num;
			temp[t][2]^=i;
			sum+=record[i];
			tt[1]=i;
			for(int k=2;k<=n;++k)
			{
				int hand=0;
				for(int j=0;j<m;++j)
				{
					if(temp[t][k-1]&1<<j)hand+=1<<j;
				}
			    handle(k,hand);
			    if(temp[t][k]&num)temp[t][k]^=num;
			    temp[t][k+1]^=hand;
				sum+=record[hand];
				tt[k]=hand;
			}
			if(temp[t][n]==0&&(ans>sum||ans==sum&&cmp()))
			{
				for(int j=1;j<=n;++j)
				re[j]=tt[j];
				ans=sum;
			}
		}
		if(ans==M)puts("IMPOSSIBLE");
		else 
		{
			for(int i=1;i<=n;++i)
			{
				for(int j=m-1;j>=0;--j)
				{
					int t;
					t=((re[i]&1<<j)==1<<j);//‘&’的优先度比‘==’低,但‘<<’的优先度比‘==’高
					cout<<t<<(j>0?' ':'\n');
				}
			}
		}
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值