POJ3279 Fliptile(状态压缩+暴力)

这篇博客探讨了一种棋盘翻转问题的解决方法,通过状态压缩和动态规划进行枚举和翻转操作。作者使用C++编写了一个程序,首先初始化棋盘状态,然后遍历所有可能的第一行翻转组合,对于每种组合,递归地更新后续行的翻转状态,并计算总翻转次数。最终,找到使最后一行全部翻转为0的最小翻转次数。如果无法达到目标状态,则输出'IMPOSSIBLE'。
摘要由CSDN通过智能技术生成

题目传送门
这个题就是类似于一个棋子反转的问题。
这道题其实就是利用状态压缩来枚举第一行到底哪一个格子需要翻动。
例如3*3的格子就要枚举 2 3 2^3 23次,
分别是
001
010
100
011
110
101
111
000
1的位置代表翻动,0的位置代表不翻动,这样的话就很明确地表示了(因为这样的二进制枚举其实就是按照字典序来枚举的)格子的翻动情况,接下来的格子就是看上一行有哪一些是1,下面的就跟着翻动就可以了。

#include<iostream>
#include<cstring>
using namespace std;
int a[20][20];
int co[20][20];int x,y;
int t[20][20];
int dx[]={0,1,0,-1};
int dy[]={1,0,-1,0};int ppp[20][20];
void copy(){
	for(int i=1;i<=x;i++){
		for(int j=1;j<=y;j++){
			co[i][j]=a[i][j];
		} 
	}
}

int solve(){
		copy();
		int ans=0;
		for(int j=1;j<=x;j++){
			for(int p=1;p<=y;p++){
				if(j!=1&&co[j-1][p]==1){
					t[j][p]=1;
				}
			
			
		
				if(t[j][p]==1){
					co[j][p]=co[j][p]^1;
					for(int k=0;k<4;k++){
						int xx=j+dx[k];
						int yy=p+dy[k];
							co[xx][yy]=co[xx][yy]^1;
					}
				}
			}
		}
		for(int i=1;i<=x;i++){
			for(int j=1;j<=y;j++){
				ans+=t[i][j];
			}
		}
		int flag=1;
		for(int i=1;i<=y;i++){
			if(co[x][i]!=0){
				flag=0;
				break;
			}
		}
		if(flag)return ans;
		return -1;
}

int main(){

	int ju=1;
	cin>>x>>y;
	for(int i=1;i<=x;i++){
		for(int j=1;j<=y;j++){
			cin>>a[i][j];
		} 
	}
	int ans=0x3f3f3f3f;
	
	for(int i=0;i<(1<<y);i++){
		memset(t,0,sizeof t);
		for(int j=0;j<y;j++)
			if(i&(1<<j)){
				t[1][j+1]=1;
			}
			int u=solve();
			//cout<<"u==="<<u<<endl;
			
		if(u!=-1){
			ju=0;
			if(ans>u){
				ans=u;
			for(int k=1;k<=x;k++){
				for(int p=1;p<=y;p++){
					ppp[k][p]=t[k][p];
				}
			}
			
			
		}	
		}
	}
	if(ju)cout<<"IMPOSSIBLE"<<endl;
	else {
		for(int i=1;i<=x;i++){
			for(int j=1;j<=y;j++){
				cout<<ppp[i][j]<<' ';
				//printf("%d ",ppp[i][j]);
			}
		cout<<"\n";
		}
	}
	return 0;
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值