[ZOJ 3353] Chess Board [搜索+状态压缩]

18 篇文章 0 订阅
17 篇文章 0 订阅

给定一个布满黑白棋的棋盘,你有四种翻法可以选,一旦选了一种翻法,在当局游戏中就只能使用这种翻法。某种翻法是指,当你翻某个棋子时,其上下左右多少个也会一起跟着翻面。问能否翻成全白,翻成全白所需要的最少步数以及所选的翻法。若多种翻法都可达到最小步数,优先使用编号小的翻法。

数据范围:15*15的棋盘,四种翻法在题面里给出,与输入无关。

对于第一种翻法,如果确定了第一排15个的情况,即翻或不翻,为了把第一排清成全白,就能知道第二排的15个的情况,以此类推就可以推到最后一排。所以枚举第一排的15个翻的情况即可。

对于剩下三种同理,枚举最后一列/第一列翻的情况即可。

代码写的可搓了...

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

int n,m,nn,mm,ans,anskind;
bool a[15][15],d[15][15];
int b[15],c[16];

inline void update(int &a,int b) {
	if (b!=-1&&(a==-1||a>b)) a=b;
}
inline int nbits(int x) {
	int ans=0;
	while (x) {
		ans+=x&1;
		x>>=1;
	}
	return ans;
}
void bitprint(int x) {
	while (x) {
		printf("%d",x&1);
		x>>=1;
	}
	printf("\n");
}
int try1(int o) {
	int ans=nbits(o);
	c[0]^=o;
	c[0]^=o<<1&mm;
	c[0]^=o>>1;
	c[1]^=o;
	for (int i=1;i<n;i++) {
		int tmp=c[i-1];
		ans+=nbits(tmp);
		c[i]^=tmp;
		c[i]^=tmp<<1&mm;
		c[i]^=tmp>>1;
		c[i+1]^=tmp;
	}
	if (c[n-1]) return -1;
	return ans;
}
int try2(int o) {
	int ans=nbits(o);
	c[0]^=o;
	c[0]^=o<<1&mm;
	c[1]^=o<<1&mm;
	c[1]^=o>>1;
	c[1]^=o;
	for (int i=1;i<n;i++) {
		int tmp=c[i-1];
		ans+=nbits(tmp);
		c[i]^=tmp;
		c[i]^=tmp<<1&mm;
		c[i+1]^=tmp<<1&mm;
		c[i+1]^=tmp>>1;
		c[i+1]^=tmp;
	}
	if (c[n-1]) return -1;
	return ans;
}
int try3(int o) {
	int ans=nbits(o);
	c[0]^=o;
	c[0]^=o<<1&mm;
	c[0]^=o>>1;
	c[1]^=o<<1&mm;
	c[1]^=o;
	for (int i=1;i<n;i++) {
		int tmp=c[i-1];
		ans+=nbits(tmp);
		c[i]^=tmp;
		c[i]^=tmp<<1&mm;
		c[i]^=tmp>>1;
		c[i+1]^=tmp<<1&mm;
		c[i+1]^=tmp;
	}
	if (c[n-1]) return -1;
	return ans;
}
int try4(int o) {
	int ans=nbits(o);
	c[0]^=o;
	c[0]^=o<<1&mm;
	c[0]^=o>>1;
	c[1]^=o<<1&mm;
	c[1]^=o>>1;
	for (int i=1;i<n;i++) {
		int tmp=c[i-1];
		ans+=nbits(tmp);
		c[i]^=tmp;
		c[i]^=tmp<<1&mm;
		c[i]^=tmp>>1;
		c[i+1]^=tmp<<1&mm;
		c[i+1]^=tmp>>1;
	}
	if (c[n-1]) return -1;
	return ans;
}
void getb() {
	int i,j;
	for (i=0;i<n;i++) {
		int tmp=0;
		for (j=0;j<m;j++) {
			tmp<<=1;
			tmp|=a[i][j];
		}
		b[i]=tmp;
	}
}
void flip1() {
	int i,j,o,oldans=ans;
	getb();
	for (o=0;o<=mm;o++) {
		memcpy(c,b,sizeof(b));
		update(ans,try1(o));
	}
	if (oldans!=ans) anskind=1;
}
void flip2() {
	int i,j,o,oldans=ans;
	getb();
	for (o=0;o<=mm;o++) {
		memcpy(c,b,sizeof(b));
		update(ans,try2(o));
	}
	if (oldans!=ans) anskind=2;
}
void flip3() {
	int i,j,o,oldans=ans;
	getb();
	for (o=0;o<=mm;o++) {
		memcpy(c,b,sizeof(b));
		update(ans,try3(o));
	}
	if (oldans!=ans) anskind=3;
}
void flip4() {
	int i,j,o,oldans=ans;
	getb();
	for (o=0;o<=mm;o++) {
		memcpy(c,b,sizeof(b));
		update(ans,try4(o));
	}
	if (oldans!=ans) anskind=4;
}

int main() {
	int i,j;
	while (scanf("%d%d",&n,&m),n!=0) {
		nn=(1<<n)-1;mm=(1<<m)-1;
		for (i=0;i<n;i++)
			for (j=0;j<m;j++) {
				char c;
				scanf(" %c",&c);
				a[i][j]=(c=='1');
			}
		ans=-1;anskind=-1;
		flip1();
		for (i=0;i<n;i++)
			for (j=0;j<m;j++) 
				d[m-j-1][i]=a[i][j];
		swap(n,m);
		nn=(1<<n)-1;mm=(1<<m)-1;
		for (i=0;i<n;i++)
			for (j=0;j<m;j++)
				a[i][j]=d[i][j];
		flip2();
		for (i=0;i+i<n;i++)
			for (j=0;j<m;j++)
				swap(a[i][j],a[n-i-1][j]);
		flip3();
		flip4();
		if (ans!=-1) printf("%d %d\n",anskind,ans);
		else printf("Impossible\n");
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值