解这题的关键思想
第一行的状态决 定了后面所有行的状态
奶牛踏瓷砖问题,显然奶牛踏 1 次和奶牛踏3次,效果是一样的,那么每块瓷砖的翻转次数,只可能是 0次或一次。
那么现在问题就转换成了枚举结果矩阵中的每一个数值是 1 还是0 ,但是 M 和 N 的最大值为 15,单纯暴力的话,2^15*15 一定会超时。
问题的关键在于前一行的状态决定了后一行的状态,所以一旦第一行确定,后面的所有行就确定了。现在就可以转化成单纯的枚举每一行或者每一列。 时间复杂度 2^15 ,很小。
起始状态 踏瓷砖次数矩阵
1 0 0 1 0 0 0 0
0 1 1 0 1 0 0 1
0 1 1 0 1 0 0 1
1 0 0 1 0 0 0 0
我实现的代码就是 枚举第一列的状态 ,计算出踏瓷砖的状态矩阵,判断最后该情况是否可取,因为照这种前一列推后一列的状态,最后一列的状态不一定是全0,所以要判断一下。
代码如下:
#include<iostream>
#include<cstring>
using namespace std;
int statu[20];
int m,n;
int maze[20][20];
int result[20][20]; //存储最终结果
int mid[20][20]; //存储枚举的结果
int mid_maze[20][20]; //存储中间变化的迷宫
int dir[4][2] = {{0,1},{0,-1},{1,0},{-1,0}};
int max_time;
void flip(int x,int y)
{
mid_maze[x][y] = (mid_maze[x][y]+1)%2;
for(int i=0;i<4;i++)
{
int px =x+dir[i][0];
int py = y+dir[i][1];
if(px<0||py<0||px>=m||py>=n) continue;
mid_maze[px][py] = (mid_maze[px][py]+1)%2;
}
}
int hasre;
int main()
{
ios::sync_with_stdio(false);
while(cin>>m>>n)
{
hasre=0;
memset(mid_maze,0,sizeof(mid_maze));
memset(maze,0,sizeof(maze));
max_time = 0x3f3f3f3f;
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
cin>>maze[i][j];
}
}
for(int pp=0; pp< 2<<n;pp++)
{
int counts = 0;
int p =pp;
memset(statu,0,sizeof(statu));
memset(mid,0,sizeof(mid));
while(p!=0)
{
statu[counts++] = p&1;
p = p>>1;
}
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
mid_maze[i][j] = maze[i][j];
counts =0;
for(int i=0;i<n;i++)
{
mid[0][i] = statu[i];
if(statu[i])
{
flip(0,i);
counts++;
}
}
for(int i=1;i<m;i++)
{
for(int j=0;j<n;j++)
{
if(mid_maze[i-1][j] ==1)
{
mid[i][j]=1;
flip(i,j);
counts++;
}
}
}
int ops=1;
for(int i=0;i<n;i++)
{
if(mid_maze[m-1][i]==1)
{
ops=0;
break;
}
}
if(ops==0)continue;
if(counts < max_time)
{
max_time = counts;
hasre=1;
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
result[i][j] = mid[i][j];
}
}
}else if(counts == max_time){
int flag=0;
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
if(result[i][j] > mid[i][j])
{
break;
flag=1;
}
}
if(flag==1)break;
}
if(flag ==1)
{
hasre =1;
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
result[i][j] = mid[i][j];
}
}
}
}
}
if(hasre ==0)
{
cout<<"IMPOSSIBLE"<<endl;
continue;
}
for(int i=0;i<m;i++)
{
cout<<result[i][0];
for(int j=1;j<n;j++)
{
cout<<" "<<result[i][j];
}
cout<<endl;
}
}
return 0;
}
最后附上一个网上大牛用该题写的小游戏
https://pan.baidu.com/s/1czj69yuvMVf_b7IbSOm-ig