POJ 3279 - Fliptile(枚举)
Farmer John knows that an intellectually satisfied cow is a happy cow who will give more milk. He has arranged a brainy activity for cows in which they manipulate an M × N grid (1 ≤ M ≤ 15; 1 ≤ N ≤ 15) of square tiles, each of which is colored black on one side and white on the other side.
As one would guess, when a single white tile is flipped, it changes to black; when a single black tile is flipped, it changes to white. The cows are rewarded when they flip the tiles so that each tile has the white side face up. However, the cows have rather large hooves and when they try to flip a certain tile, they also flip all the adjacent tiles (tiles that share a full edge with the flipped tile). Since the flips are tiring, the cows want to minimize the number of flips they have to make.
Help the cows determine the minimum number of flips required, and the locations to flip to achieve that minimum. If there are multiple ways to achieve the task with the minimum amount of flips, return the one with the least lexicographical ordering in the output when considered as a string. If the task is impossible, print one line with the word “IMPOSSIBLE”.
Input
Line 1: Two space-separated integers: M and N
Lines 2…M+1: Line i+1 describes the colors (left to right) of row i of the grid with N space-separated integers which are 1 for black and 0 for white
Output
Lines 1…M: Each line contains N space-separated integers, each specifying how many times to flip that particular location.
Sample Input
4 4
1 0 0 1
0 1 1 0
0 1 1 0
1 0 0 1
Sample Output
0 0 0 0
1 0 0 1
1 0 0 1
0 0 0 0
农夫约翰知道,一头知识上满意的母牛是能多产牛奶的快乐母牛。他为母牛安排了脑力活动,他们操纵M×N格子(1≤M≤15; 1≤N≤15)的正方形砖,每块砖的一侧为黑色,另一侧为白色。
就像人们猜测的那样,当翻转单个白色图块时,它会变为黑色。翻转单个黑色瓷砖时,它将变为白色。母牛在翻转砖块时会得到奖励,因此每块砖块的白色侧面都朝上。但是,奶牛的蹄子相当大,当他们尝试翻转某个瓷砖时,它们也会翻转所有相邻的瓷砖(与翻转后的瓷砖共享完整边缘的瓷砖)。由于翻转很累,奶牛希望尽量减少翻转次数。
帮助奶牛确定所需的最小翻转次数,以及达到该最小翻转的位置。如果有多种方法可以以最少的翻转次数来完成任务,则当将其视为字符串时,以输出中词典顺序最少的方式返回。如果无法完成任务,请用“ IMPOSSIBLE”一词打印一行。
输入项
第1行:两个以空格分隔的整数:M和N
第2…M + 1行:第i + 1行用N个以空格分隔的整数描述网格第i行的颜色(从左到右),黑色为1,白色为0
输出量
第1…M行:每行包含N个以空格分隔的整数,每个整数指定翻转该特定位置的次数。
样本输入
4 4
1 0 0 1
0 1 1 0
0 1 1 0
1 0 0 1
样本输出
0 0 0 0
1 0 0 1
1 0 0 1
0 0 0 0
题目大意:
给出 m x n 的地图,均由0和1组成,翻转每一个格子都会使自己以及上下左右四个方向的格子翻转,询问是否能通过一定次数的翻转得到全0,如果可以输出翻转位置的地图,如果不可以则输出“IMPOSSIBLE”。
解题思路:
通过题目了解到m n 的范围只有15,所以可以直接暴力枚举,我们枚举第一行的状态,第一行一共有最多(2^15)种状态,所以直接全部枚举出来就可以。因为第一行的状态一旦确定,其他行的方案也就确定了,然后从第二行推到m-1行,每一次枚举第i行都将第i-1行的格子全部置0,最后判断第m行是不是全0,如果全0则说明可以。存一下地图和步数,继续枚举,直到全部枚举完即可。AC代码:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 20;
int mp[N][N],res=0x3f3f3f3f;//存地图和当前步数
int tmp[N][N];//每一次枚举的临时地图
int ans[N][N];//存答案
int m,n;
int nt[][2]={{-1,0},{1,0},{0,0},{0,-1},{0,1}};//5个方向
int getsum(int x,int y)//得到该点的状态,此处的tmp[i][j]表示的是这个点翻转了几次,
{
int cnt=mp[x][y];
for(int i=0;i<5;i++)
{
int nx=x+nt[i][0];
int ny=y+nt[i][1];
cnt+=tmp[nx][ny];
}
return cnt%2;
}
int solve()
{
int cnt=0;
for(int i=1;i<m;i++)
for(int j=0;j<n;j++)
if(getsum(i-1,j))//如果这个格子是1则直接翻转
tmp[i][j]=1;
for(int i=0;i<n;i++)//判断最后一行所有格子的状态
if(getsum(m-1,i))
return 0x3f3f3f3f;
for(int i=0;i<m;i++)//如果走到这一步说明此方案可行
for(int j=0;j<n;j++)
cnt+=tmp[i][j];
return cnt;
}
int main()
{
cin>>m>>n;
for(int i=0;i<m;i++)
for(int j=0;j<n;j++)
cin>>mp[i][j];
for(int i=0;i<=(1<<n);i++)//枚举第一行的所有状态
{
memset(tmp,0,sizeof tmp);//tmp初始化
for(int j=0;j<n;j++)//tmp第一行的状态初始化
tmp[0][j]=(i>>(n-j-1))&1;
int sum=solve();//判断此方案是否可行
if(sum<res)
{
res=sum;
memcpy(ans,tmp,sizeof tmp);
}
}
if(res==0x3f3f3f3f)
cout<<"IMPOSSIBLE"<<endl;
else
{
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
cout<<ans[i][j]<<" ";
cout<<endl;
}
}
//system("pause");
return 0;
}