1. 程式人生 > >Fliptile DFS (POJ-3279)

Fliptile DFS (POJ-3279)

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

 

題目大意

給一個N行M列的矩陣,值分別為0和1,每次你可以選擇將一個變成相反狀態,同時,它周圍的四個數也會變為相反狀態。
問:最少翻轉多少次,可以將所有值都變成0
多個解,輸出翻轉次數最少的(若有次數相同解,輸出字典序小的)
若無解,輸出”IMPOSSIBLE”

思路

對於每個點,只能有兩種操作,翻或不翻,若暴力所有可能性,需要2^(M*N)次操作,顯然不可行
所以有了這個法子。
先列舉第一行的所有可能性(2^M),搜尋或位運算均可
然後,對座標(i, j)來說,如果(i-1, j)不為0,那麼(i, j)必然需要翻轉。
重複進行上操作由2至N
此時,最後一行也已翻轉完畢,如果最後一行全為0,得出結果
第一行的所有結果中取最小值

程式碼

//難點在於通過對第一層的判定,從而推匯出下一城的結果所以複雜度為O(15*(2^15) )
#include "bits/stdc++.h"


using namespace std;

int f[20][20],g[20][20];
int ans[20][20];
int minn=0x3f3f3f3f;
bool judge(int n,int m)
{
	for(int i=1;i<=m;i++)
	{
		if(( f[n][i]+f[n][i-1]+f[n][i+1]+f[n-1][i]+g[n][i])&1)
		return false;
	}
	return true;
}
void dfs(int n,int m,int k,int num)
{
	int cnt=0;
	if(minn<num)
	{
		return;
	}
	if(k>n)
	{
		if(judge(n,m)&&minn>num)
		{
			memcpy(ans,f,sizeof(f));
			minn = num;
		}
		return;
	}
	
	for(int i=1;i<=m;i++)
	{
		if((f[k-2][i]+f[k-1][i-1]+f[k-1][i+1]+f[k-1][i]+g[k-1][i])&1)
		{
			f[k][i]=1;
			cnt++;
		}
		else
		f[k][i]=0;
	}
	dfs(n,m,k+1,num+cnt);
}
//這段程式碼可以有意識的記憶,通過遞迴獲取每一種可能性,但是用迴圈也是可以寫的
/*
int f[20];
for(int i=1;i<=(1<<n);i++)
{
	for(int j=0;j<=14;j++)
	{
		if(i>>j&1)
		{
			f[j]=1;
		}
		else
		f[j]=0;
	}
}
*/
void todfs(int n,int m,int k,int num)
{
	if(k>m)
	{
		dfs(n,m,2,num);
		return;
	}
	f[1][k]=0;//沒有反轉 
	todfs(n,m,k+1,num);
	f[1][k]=1;
	 todfs(n,m,k+1,num+1);
	 f[1][k]=1;
}
int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			cin>>g[i][j];
		}
	}
	todfs(n,m,1,0);
	if(minn==0x3f3f3f3f)
	cout<<"IMPOSSIBLE"<<endl;
	else
	{
		for(int i=1;i<=n;i++)
		{
			for(int j=1;j<=m;j++)
			cout<<ans[i][j]<<' ';
			cout<<endl;
		}
	}
	
	return 0;
 }