比较纠结的一道题,改了好几次才对。
首先需要知道的就是每个点如果重复点2次是没有任何意义的,所以一个点只有选或者不选,那么时间复杂度最大为2^25
毫无疑问超过了允许的范围,那么考虑减枝。
由于是3 X 3 的改变范围,所以如果 当前走到了第三行,那么就没办法更改第一行的状态,如果走到了第四行就无法更改第一 二行的状态,所以如果这个时候第一 二行
还没改成亮的它永远也不可能亮了。
最后一个就是需要输出按开关的次数最小的方案,一开始没看见,WA了好几次。。
14171735 | 10318 | Security Panel | Accepted | C++ | 0.076 | 2014-09-09 11:49:25 |
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
int n,m,OK;
int mat[15];
const int dir[11][2] = {{-1,-1},{-1,0},{-1,1},{0,-1},{0,0},{0,1},{1,-1},{1,0},{1,1}};
int Map[30];
int rote[30],_rote[30];
bool Input(){
scanf("%d%d",&n,&m);
if(!n && !m) return false;
for(int i = 0 ,k = 0; i < 3 ; i++){
char str[10];
scanf("%s",str);
for(int j = 0 ; j < 3 ; j ++){
if(str[j] == '.')
mat[k++] = 0;
else if(str[j] == '*')
mat[k++] = 1;
}
}
return true;
}
void DFS(int pos,int cur){/*位置,n行,m列,当前按了几个按钮*/
int x = pos / m;
int y = pos % m;
if(pos == 3 * m){
for(int i = 0 ; i < m ;i ++)
if(Map[i] != 1)
return ;
}
if(pos == 4 * m){ /*在第四行,前面2行的情况就固定了*/
for(int i = 0 ; i < 2 * m; i++)
if(Map[i] != 1)
return ;
}
if(pos == m * n){
for(int i = 0 ; i < pos ; i++)
if(Map[i] != 1) return ;
if(cur < OK){
OK = cur;
memcpy(_rote,rote,sizeof(rote));
}
return ;
}
/*是否对这个点进行更改,或者不更改*/
rote[pos] = 0;
DFS(pos + 1,cur); /*不更改直接走下一个点*/
/*对这个点进行更改*/
for(int i = 0 ; i < 9 ; i++){
int _x = x + dir[i][0];
int _y = y + dir[i][1];
if(_x >= 0 && _x < n && _y >= 0 && _y < m && mat[i]){
int _pos = _x * m + _y;
Map[_pos] = - Map[_pos];
}
}
rote[pos] = 1;
DFS(pos + 1,cur + 1);
/*记得把状态改回去*/
for(int i = 0 ; i < 9 ; i++){
int _x = x + dir[i][0];
int _y = y + dir[i][1];
if(_x >= 0 && _x < n && _y >= 0 && _y < m && mat[i]){
int _pos = _x * m + _y;
Map[_pos] = - Map[_pos];
}
}
return ;
}
int main(){
int Case = 1;
while(Input()){
memset(Map,-1,sizeof(Map));
memset(rote,0,sizeof(rote));
OK = 100;
DFS(0,0);
printf("Case #%d\n",Case++);
if(OK < 100){
int k = 0;
for(int i = 0 ; i < n * m ; i++){
if(_rote[i]){
if(k) printf(" ");
printf("%d",i + 1);
k++;
}
}
printf("\n");
}
else
printf("Impossible.\n");
}
return 0;
}