思路:
- 本题看似搜索,实为枚举,关键在于题目要求输出反转串从小到大的解。
- 第一版代码:dfs,只不过将搜索改成从右下到左上的副对角线搜索。但是肯定是不对的,因为所有格子都是相关联的(这点在下文详述),根本就不能满足题意。
- 第二版代码,将所有搜索得到的解串存成优先队列,最后输出 Q.top()。理论上可行,但是会 TLE。注意:要求出任意解和所有解只差一行代码,即
if(ok) return ;
- 至此,黔驴技穷,只好搜题解,由HelloWorld10086的BLOG明白了做法。详述如下:
- (第一次)状态压缩,将图形存成一个 列数(N) 位的二进制数。
- 整个图形的翻转方式是牵一发而动全身的,形象地说:如果确定了某一行(列)翻转哪些格子,那么整个图形的反转方式也一并确定,即在这种情况下不可能出现两种方法都满足题意。
原因:以固定第一行为例,在某种方案中,翻转了第一行该翻转的格子后,就再也不能碰第一行了。那么此时第一行的黑色格子 (mp[1][j]) 怎么办呢,只能是翻转它下面一行的同一列的格子 mp[2][j]。并且对于任意此时第一行的白色格子 (mp[1][k]),绝不允许动 (mp[2][k])。证毕。
- 题目要求输出最小串,就从第一行全部不翻转开始,从后边枚举。
代码:
#include
#include
using namespace std;
const int maxn = 20;
int M,N;
int K;
bool ok = false;
bool mp [maxn][maxn];
bool vis[maxn][maxn];
int moveto[4][2] = {1,0 , -1,0 , 0,1 , 0,-1};
bool check(int x,int y){
if(x < 1 || y < 1 || x > M || y > N)
return false;
return true;
}
void flip(int x,int y){
for(int k=0;k<4;k++){
int nx = x + moveto[k][0];
int ny = y + moveto[k][1];
if(check(nx , ny))
mp[nx][ny] = !mp[nx][ny];
}
mp [x][y] = !mp [x][y];
vis[x][y] = !vis[x][y];
return ;
}
bool Overall(){
for(int i=1;i<=M;i++)
for(int j=1;j<=N;j++)
if(mp[i][j]){
return false;
}
return true;
}
void dfs(int x,int y,int deep){
if(deep == K){
ok = Overall();
return ;
}
if(!x)
return ;
flip(x,y);
if(y > 1)
dfs(x , y - 1 , deep + 1);
else
dfs(x - 1 , N , deep + 1);
if(ok) return ;
flip(x,y);
if(y > 1)
dfs(x , y - 1 , deep);
else
dfs(x - 1 , N , deep);
return ;
}
int main(){
cin>>M>>N;
memset(vis , 0 , sizeof(vis));
for(int i=1;i<=M;i++)
for(int j=1;j<=N;j++)
cin>>mp[i][j];
for(K = 0 ; K <= M*N ; K++){
dfs(M,N,0);
if(ok)
break;
}
if(ok)
for(int i=1;i<=M;i++)
for(int j=1;j<=N;j++)
if(j == N)
cout<<vis[i][j]<<endl;
else
cout<<vis[i][j]<<' ' ;
else
cout<<"IMPOSSIBLE"<<endl;
return 0;
}
#include
#include
#include
#include
using namespace std;
const int maxn = 20;
int M,N;
int K;
int t;
bool ok = false;
bool mp [maxn][maxn];
bool vis[maxn][maxn];
int moveto[4][2] = {1,0 , -1,0 , 0,1 , 0,-1};
priority_queue <string , vector<string> , greater<string> > Q;
bool check(int x,int y){
if(x < 1 || y < 1 || x > M || y > N)
return false;
return true;
}
void flip(int x,int y){
for(int k=0;k<4;k++){
int nx = x + moveto[k][0];
int ny = y + moveto[k][1];
if(check(nx , ny))
mp[nx][ny] = !mp[nx][ny];
}
mp [x][y] = !mp [x][y];
vis[x][y] = !vis[x][y];
return ;
}
bool Overall(){
for(int i=1;i<=M;i++)
for(int j=1;j<=N;j++)
if(mp[i][j]){
return false;
}
return true;
}
void dfs(int x,int y,int deep){
if(deep == K){
string str;
ok = Overall();
if(ok){
for(int i=1;i<=M;i++)
for(int j=1;j<=N;j++)
str += vis[i][j] + '0';
Q.push(str);
}
return ;
}
if(!x)
return ;
flip(x,y);
if(y > 1)
dfs(x , y - 1 , deep + 1);
else
dfs(x - 1 , N , deep + 1);
flip(x,y);
if(y > 1)
dfs(x , y - 1 , deep);
else
dfs(x - 1 , N , deep);
return ;
}
int main(){
cin>>M>>N;
memset(vis , 0 , sizeof(vis));
for(int i=1;i<=M;i++)
for(int j=1;j<=N;j++)
cin>>mp[i][j];
for(K = 0 ; K <= M*N ; K++){
while(!Q.empty())
Q.pop();
dfs(M,N,0);
if(!Q.empty())
break;
}
if(!Q.empty()){
string str = Q.top();
for(string::iterator i = str.begin() ; i != str.end() ; i++)
if((i - str.begin() + 1) % N == 0)
cout<<*i<<endl;
else
cout<<*i<<' ' ;
}
else
cout<<"IMPOSSIBLE"<<endl;
return 0;
}
#include
#include
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 20;
int M,N;
const int moveto[5][2] = {0,0 , 1,0 , -1,0 , 0,1 , 0,-1};
bool mp [maxn][maxn];
bool rec[maxn][maxn];
bool vis[maxn][maxn];
bool cur[maxn][maxn];
int ans = INF;
void flip(int x,int y){
vis[x][y] = true;
for(int i=0;i<5;i++){
int nx = x + moveto[i][0];
int ny = y + moveto[i][1];
cur[nx][ny] = !cur[nx][ny];
}
return ;
}
bool Overall(){
for(int i=1;i<=M;i++)
for(int j=1;j<=N;j++)
if(cur[i][j])
return false;
return true;
}
void solve(int t){
memset(vis , 0 , sizeof(vis));
memcpy(cur , mp , sizeof(mp));
int cnt = 0;
for(int i=0 ; (1<<i) <= t ; i++){
if((1<<i) & t){
flip(1 , N-i);
cnt++;
}
}
for(int i=2;i<=M;i++){
for(int j=1;j<=N;j++){
if(cur[i-1][j]){
flip(i , j);
cnt++;
}
}
}
if(Overall() && ans > cnt){
memcpy(rec , vis , sizeof(vis));
ans = cnt;
}
return ;
}
int main(){
cin>>M>>N;
for(int i=1;i<=M;i++)
for(int j=1;j<=N;j++)
cin>>mp[i][j];
for(int t = 0 ; t < (1<<N) ; t++){
solve(t);
}
if(ans == INF)
cout<<"IMPOSSIBLE"<<endl;
else{
for(int i=1;i<=M;i++)
for(int j=1;j<=N;j++)
if(j < N)
cout<<rec[i][j]<<' ';
else
cout<<rec[i][j]<<endl;
}
return 0;
}