-->Fliptile
直接中文翻譯:
Descriptions:
給你一個01矩陣,矩陣大小為M x N。(1 <= M , N <= 15)
每次操作選擇一個格子,使得該格子與上下左右四個格子的值翻轉。
至少多少次操作可以使得矩陣中所有的值變為0?
請輸出翻轉方案,若沒有方案,輸出"IMPOSSIBLE” 。
若有多種方案符合題意,請首先輸出翻轉次數最少的方案;若方案個數仍不唯一,則輸出字典序最小的方案。
Input
第一行輸入兩個數:M和N。(1 <= M , N <= 15)
接下來M行,每行N個數,其值只為0或1。
Output
輸出M行,每行N個數。
每個數代表該位置翻轉次數
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
題目鏈接:
https://vjudge.net/problem/POJ-3279
先按字典順序枚舉第一行的全部可能,再去推第2行,第3行......把這些行全部推成0,最后看最后一行,如果最后一行都是0,則成功,記錄翻轉次數。否則失敗
AC代碼:
#include <iostream> #include <cstdio> #include <fstream> #include <algorithm> #include <cmath> #include <deque> #include <vector> #include <queue> #include <string> #include <cstring> #include <map> #include <stack> #include <set> #include <sstream> #define mod 1000000007 #define eps 1e-6 #define ll long long #define INF 0x3f3f3f3f #define MEM(x,y) memset(x,y,sizeof(x)) #define Maxn 20 using namespace std; int result; int n,m; int mp[Maxn][Maxn];//原始地圖 int tmp[Maxn][Maxn];//當前操作的地圖 int ans[Maxn][Maxn];//最優解地圖 int dt[][2] = { { -1, 0 }, { 1, 0 }, { 0, 0 }, { 0, -1 }, { 0, 1 } };//5個方向 int getcolor(int x,int y)//得到(x,y)的顏色 { int cnt=mp[x][y]; for(int i=0; i<5; i++) { int tx=dt[i][0]+x; int ty=dt[i][1]+y; if(tx>=0&&tx<n&&ty>=0&&ty<m) cnt+=tmp[tx][ty]; } return cnt%2; } int solve() { int cnt=0; for(int i=1; i<n; i++)//從第二行開始檢查是否需要翻轉 for(int j=0; j<m; j++) if(getcolor(i-1,j)) tmp[i][j]=1; for(int i=0; i<m; i++)//檢查最后一行是否全為0 if(getcolor(n-1,i)) return INF; for(int i=0; i<n; i++)//統計翻轉次數 for(int j=0; j<m; j++) cnt+=tmp[i][j]; return cnt; } int main() { result=INF; cin>>n>>m; for(int i=0; i<n; i++) for(int j=0; j<m; j++) cin>>mp[i][j]; for(int i=0; i<1<<m; i++)//按照字典序枚舉第一行所以翻轉可能 { MEM(tmp,0);//初始化地圖 for(int j=0; j<m; j++) tmp[0][j]= i>>(m-(j+1)) & 1;//第一行的狀態 int sum=solve();//翻轉的次數 if(sum<result)//更新地圖 { result=sum; memcpy(ans,tmp,sizeof tmp);//tmp數組復制到ans } } if(result==INF) cout<<"IMPOSSIBLE"<<endl; else//輸出 { for(int i=0; i<n; i++) { for(int j=0; j<m; j++) cout<<ans[i][j]<<" "; cout<<endl; } } }