标签:uva
题意:
给出一个最多面板,上面有很多按钮,亮着或没亮,初始是全部没亮;从左上到右下,编号从1开始;,
现在我们给出一个3*3的矩阵,作为按钮规则;
例如
.*.
***
.*.
也就是你按任意建,都把这个建单做是这个3*3矩阵的中间,按照这个图,也就是按一个键,则这个建还有它的上下左右,状态全都转变(如果它已经没有上一行了,则忽略);
给出r,c代表几行几列
然后给出一个固定的3*3的矩阵;表示按钮的规则
问最少按几个全部按钮都亮;
思路:
首先算出每一个按钮的影响有哪几个,用二进制压缩;
影响编号1的,则第一位是1,不影响的按钮位置用0;
然后dfs直接暴力;
注意有一个剪枝可以减少很多时间,就是你已经遍历到第n行,如果第n-2行还有没亮的按钮,则就直接退出,因为一个按钮最多影响到它上一行,上两行没亮的就永远不会亮了;
#include<cstdio> #include<cstring> #include<set> #define ll long long using namespace std; const int N = 30; struct pos { int x,y; }p[N]; char g[3][3]; int res[N]; int temp[N]; ll s[N]; bool ok; int num,r,c,ans; void init() { for(int i = 0; i < (r * c); i++) { int rr = i / c; int cc = i % c; for(int j = 0; j < num;j++) { int x = rr + p[j].x; int y = cc + p[j].y; if(x < 0 || y < 0 || x >= r || y >= c) continue; ll num = (x * c + y); s[i] |= (1 << num); } } } void dfs(int cur,int S,int len) { if(S == ((1 << (r * c)) - 1) && len < ans) { ok = 1; for(int i = 0; i < r * c; i++) { res[i] = temp[i]; } return; } if((cur / c) >= 2) { int k = (cur/c) - 2; for(int i = k * c; i < k * c + c; i++) { if(!(S & (1 << i))) return ; } } if(cur == (r * c)) return; temp[cur] = 1; dfs(cur + 1, S ^ s[cur],len + 1); temp[cur] = 0; dfs(cur + 1, S, len); } int main() { int cas = 1; while(scanf("%d%d",&r, &c) == 2) { for(int i = 0 ; i < 3; i++) { scanf("%s",g[i]); } ok = 0; memset(s, 0, sizeof(s)); memset(temp, 0, sizeof(temp)); num = 0; ans = 0x3f3f3f3f; for(int i = 0; i < 3; i++) { for(int j = 0; j < 3; j++) { if(g[i][j] == '*') { p[num].x = i - 1; p[num++].y = j - 1; } } } init(); printf("Case #%d\n",cas++); dfs(0,0,0); bool f = 0; if(ok) { for(int i = 0 ; i < r * c; i++) { if(res[i] == 1) { if(f) printf(" "); if(!f) f = 1; printf("%d",i + 1); } } } if(!ok) printf("Impossible."); printf("\n"); } }
标签:uva
原文地址:http://blog.csdn.net/yeyeyeguoguo/article/details/45178135