poj1222 开关问题

传送门:https://vjudge.net/problem/POJ-1222

题意:给你一个5行6列的0,1矩阵,代表着灯的亮灭,0灭,1亮。对一个灯进行开关转换时,它的上下左右灯都会转换。要让所有灯都灭(就是让它全为0)。问方案,不是最小操作数!!!

这题是从挑战程序设计竞赛来的。(可以先看较简单的一道开关问题:https://www.cnblogs.com/xiaobuxie/p/10847096.html)其实开关问题具体思路就是:首先,每一个位置要么转换一次,要么不转换。这个很好理解。其次就是,先往小的想,先假设最开始的灯的开关状态已经确定了,但是这样的开关状态未必会使它灭,所以要让它灭,接下来那一个开关状态就确定了。不懂的,可以去看简单那题。

具体的说,我们先看左上角那盏灯,影响它的状态有右边和下边还有它自己。所以我们先枚举第一行的转换状态(具体看代码)。然后从第二行开始往下枚举。不如说我枚举到第i行,第j列,要确定它的转换状态。我们知道

对于(i-1,j),影响它的有(i-1,j),(i-1,j+1),(i-1,j-1),(i-2,j)以及(i,j),由于我枚举的顺序,前面四个转换状态都已经确定了,所以要让(i-1,j)灭,那么(i,j)的转换状态就确定了,也就是说确定(i,j)的转换状态,不是为了让自己灭,而是为了让它上面那一个灭,而要让自己灭,那就要靠后面的灯了。

然后最后那一行灯都是为了倒数第二行灭而确定的转换状态,所以最后一行不保证全都灭,因此最后要检查一下最后一行是否全为0。

 1 // Cease to struggle and you cease to live
 2 #include <iostream>
 3 #include <cmath>
 4 #include <cstdio>
 5 #include <cstring>
 6 #include <algorithm>
 7 #include <queue>
 8 #include <vector>
 9 #include <set>
10 #include <map>
11 #include <stack>
12 using namespace std;
13 typedef long long ll;
14 int a[10][10];
15 int op[10][10];
16 int dx[4]={-1,0,0,0};
17 int dy[4]={0,0,-1,1};
18 bool solve(){
19     for(int i=2;i<=5;++i){
20         for(int j=1;j<=6;++j){
21             int x=i-1,y=j;
22             int sum=a[x][y];
23             for(int u=0;u<4;++u){
24                 int xx=x+dx[u],yy=y+dy[u];
25                 if(xx<1 || xx>5 || yy<1 || yy>6) continue;
26                 sum+=op[xx][yy];
27             }
28             if(sum%2) op[i][j]=1;
29             else op[i][j]=0;
30         }
31     }
32     for(int i=1;i<=6;++i){
33         int x=5,y=i;
34         int sum=a[x][y];
35         for(int u=0;u<4;++u){
36             int xx=x+dx[u],yy=y+dy[u];
37             if(xx<1 || xx>5 || yy<1 || yy>6) continue;
38             sum+=op[xx][yy];
39         }
40         if(sum%2) return 0;
41     }
42     return 1;
43 }
44 int main(){
45     int n;scanf("%d",&n);
46     for(int t=1;t<=n;++t){
47         for(int i=1;i<=5;++i){
48             for(int j=1;j<=6;++j)
49                 scanf("%d",&a[i][j]);
50         }
51         for(int i=0;i<(1<<6);++i){
52             for(int j=1;j<=6;++j){
53                 op[1][j]=(i>>(6-j))&1;
54             }
55             if(solve()) break;
56         }
57         printf("PUZZLE #%d\n",t);
58         for(int i=1;i<=5;++i){
59             for(int j=1;j<=6;++j)
60                 printf("%d ",op[i][j]);
61             cout<<endl;
62         }
63     }
64     return 0;
65 }
View Code

 

posted @ 2019-05-11 11:59  小布鞋  阅读(346)  评论(0编辑  收藏  举报