比较纠结的一道题,改了好几次才对。
首先需要知道的就是每个点如果重复点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; }
时间: 2024-10-13 00:53:10