题目链接
思路:
-
因为刚做完Flip Game嘛,很快就敲出了第一版代码~
-
可是TLE了,又没有别的办法,只能尝试把判断符号 ‘+’‘-’ 改成判断 bool 这样子…也过了…
-
然后WA…先贴出WA部分,你可以试着想想为什么。
//这里是dfs()中的第一部分:停搜条件
if(flag)
return ;
if(row == 5)
return ;
if(deep == step){
flag = judge();
return ;
}
- 答案是:第二和第三,这两个判断条件写反了。
- 明白了吗?设想一种情况,这种情况下正解的最后一步是将 mp[4][4] 取反。因为翻转 mp[4][4] 后进入的是对下一个格子(mp[5][1])的深搜,这时候若先判断本格是否合法,那么就没法改变flag了。答案被跳过,最后程序运行结果是一行孤零零的数字17。
- 这两个坑填平,就AC啦。
然后去网上看到了更好的解法,也不难理解,在此复述一遍:
- 首先要明确一个结论:以 mp[i][j] 为例,若我们对所有属于第 i 行或第 j 列的七个格子都做一次本题所述的操作(即一共进行七七四十九次单格取反),则最后只有 mp[i][j] 这一个格子被取反。
- 其次,对任何一个格子,在一局游戏中只有两种可能:不取反、取反。
- 并且要知道,在整局游戏的尺度下,对两次不同的题述操作来说,它们的操作时间和顺序对结果没有任何影响。
- 如此,我们就可以对原棋盘每个 ‘+’ 所属的家族中的所有家族成员(其实就是以它为中心的七个格子啦)操作数加一,并且使用第二条结论,把操作数加一定义为对它的 reverse 取反。
- 最后,所有需要reverse的格子数量就是最小操作数,把他们所在的位置输出就是操作的位置啦。
代码:
- TLE版本
#include <iostream>
#include <algorithm>
using namespace std;
char mp[6][6];
bool flag = false;
int movement[16][2];
int t=0;
int step;
void input(){
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++)
cin>>mp[i][j];
return ;
}
bool judge(){
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++)
if(mp[i][j] == '+')
return false;
return true;
}
void flip(int row,int col){
if(mp[row][col] == '-')
mp[row][col] = '+';
else
mp[row][col] = '-';
for(int i=1;i<=4;i++){
if(mp[i][col] == '-')
mp[i][col] = '+';
else
mp[i][col] = '-';
}
for(int j=1;j<=4;j++){
if(mp[row][j] == '-')
mp[row][j] = '+';
else
mp[row][j] = '-';
}
return ;
}
void dfs(int row,int col,int deep){
if(flag)
return ;
if(deep == step){
flag = judge();//first
return ;
}//注意这两个函数不能写反,因为有可能是翻完mp[4][4],才是正解
//如果得到正解后,先判断下一格是否越界,flag就没机会改变
if(row == 5)//second
return ;
flip(row,col);
movement[t][0] = row;
movement[t][1] = col;
t++;
if(col < 4)
dfs(row , col+1 , deep+1);
else
dfs(row+1 , 1 , deep+1);
if(flag)
return ;
flip(row,col);
t--;
if(col < 4)
dfs(row , col+1 , deep);
else
dfs(row+1 , 1 , deep);
return ;
}
void output(){
cout<<step<<endl;
for(int i=0;i<t;i++)
cout<<movement[i][0]<<' '<<movement[i][1]<<endl;
return ;
}
int main(){
input();
for(step = 1 ; step <= 16 ; step++){
dfs(1,1,0);
if(flag)
break;
}
output();
return 0;
}
- 正解版本:648K 469MS
//648K 469MS
#include <iostream>
#include <algorithm>
using namespace std;
bool mp[6][6];
bool flag = false;
int movement[16][2];
int t=0;
int step;
void input(){
char tp;
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++){
cin>>tp;
if(tp == '-')
mp[i][j] = true;
else
mp[i][j] = false;
}
return ;
}
bool judge(){
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++)
if(!mp[i][j])
return false;
return true;
}
void flip(int row,int col){
mp[row][col] = !mp[row][col];
for(int i=1;i<=4;i++)
mp[i][col] = !mp[i][col];
for(int j=1;j<=4;j++)
mp[row][j] = !mp[row][j];
return ;
}
void dfs(int row,int col,int deep){
if(flag)
return ;
if(deep == step){
flag = judge();//first
return ;
}//注意这两个函数不能写反,因为有可能是翻完mp[4][4],才是正解
//如果得到正解后,先判断下一格是否越界,flag就没机会改变
if(row == 5)//second
return ;
flip(row,col);
movement[t][0] = row;
movement[t][1] = col;
t++;
if(col < 4)
dfs(row , col+1 , deep+1);
else
dfs(row+1 , 1 , deep+1);
if(flag)
return ;
flip(row,col);
t--;
if(col < 4)
dfs(row , col+1 , deep);
else
dfs(row+1 , 1 , deep);
return ;
}
void output(){
cout<<step<<endl;
for(int i=0;i<t;i++)
cout<<movement[i][0]<<' '<<movement[i][1]<<endl;
return ;
}
int main(){
input();
for(step = 1 ; step <= 16 ; step++){
dfs(1,1,0);
if(flag)
break;
}
output();
return 0;
}
- 锦囊版本:640K 125MS
//640K 125MS
#include <iostream>
#include <cstring>
using namespace std;
bool mp[6][6];
bool reverse[6][6];
int ans = 0;
void input(){
memset(mp,0,sizeof(mp));
char tp;
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++){
cin>>tp;
if(tp == '-')
mp[i][j] = true;
}
return ;
}
void reverseone(int x,int y){
reverse[x][y] = !reverse[x][y];
for(int i=1;i<=4;i++)
reverse[i][y] = !reverse[i][y];
for(int j=1;j<=4;j++)
reverse[x][j] = !reverse[x][j];
return ;
}
void output(){
cout<<ans<<endl;
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++)
if(reverse[i][j])
cout<<i<<' '<<j<<endl;
return ;
}
int main(){
input();
memset(reverse,0,sizeof(reverse));
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++)
if(!mp[i][j])
reverseone(i,j);
for(int i=1;i<=4;i++)
for(int j=1;j<=4;j++)
if(reverse[i][j]) ans++;
output();
return 0;
}