您的位置:首页 > 其它

D - Flip tile

2015-07-15 15:03 495 查看
题目大意翻瓷砖(姑且认为题目就是这个意思吧) 农民约翰知道越聪明越快乐的牛产的牛奶越多(神马鬼理论),于是他开始安排牛进行一个智力运动在一个M*N (1 ≤ M ≤ 15; 1 ≤ N ≤ 15) 的网格中,每个网格都有一个正方形的瓷砖组成,当然每块瓷砖都是由黑色和白色两种颜色组成的。 这个游戏是吧所有的瓷砖都变成白色??,奶牛在翻转瓷砖的时候会把四周的瓷砖一同翻转过来的,当然奶牛想用最少的步骤来翻转,如果有多种翻转方法,输出字典序最小的那个(矩形的字典序。。。。),如果不能完成翻转,输出IMPOSSIBLE。

通过观察可以看出来一共有 2 ^(M*N)种翻转方式,当然不能一种一种的实验,那样会超时到死的,不过通过观察可以看出来只要第一行的翻转方案确认了,那么下面的也可以知道了,因为如果有一个瓷砖需要翻转,本行翻转方法已经确认,那么一定在同列的下行翻转。这样只需要2^15就够了。写一下试试吧........

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<queue>
using namespace std;

#define maxn 30
const int oo = 0xffffff;

//本身和四周的位置,因为需要保存翻转的方法,所以不改变上层
int dir[4][2] = { {0,0},{0,1},{0,-1},{1,0} };
int G[maxn][maxn], ans[maxn][maxn];
int M, N;

//初始化第0层并且复制图到ans
void Start(int k)
{
int i, j;

for(i=N; i>0; i--)
{
ans[0][i] = k%2;
k /= 2;
}

for(i=1; i<=M; i++)
for(j=1; j<=N; j++)
ans[i][j] = G[i][j];
}
int OK()//判断翻转后的图是否合法
{
int i;

for(i=1; i<=N; i++)
if(ans[M][i])return 0;

return 1;
}
//翻转图,并且返回需要翻转的步数,若不能翻转成功则返回-1
int OverTurn()
{
int i, j, k, sum=0;

for(i=1; i<=M; i++)
for(j=1; j<=N; j++)
{
if(ans[i-1][j])
{
for(k=0; k<4; k++)
{
sum++;
int ni = i+dir[k][0];
int nj = j+dir[k][1];

ans[ni][nj] = !ans[ni][nj];
}
}
}

if(OK() == 0)
return -1;

return sum;
}

int main()
{
while(scanf("%d%d", &M, &N) != EOF)
{
int i, j, k=pow(2, N);
int sum = oo, p, q=-1;//sum 需要翻转的步数

for(i=1; i<=M; i++)
for(j=1; j<=N; j++)
scanf("%d", &G[i][j]);

for(i=0; i<=k; i++)
{
Start(i);
p = OverTurn();

if(p != -1 && sum > p)
sum = p, q = i;
}

if(q == -1)
printf("IMPOSSIBLE\n");
else
{
Start(q);
OverTurn();

for(i=0; i<M; i++)
for(j=1; j<=N; j++)
printf("%d%c", ans[i][j], j==N?'\n':' ');
}
}

return 0;}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: