https://www.cnblogs.com/violet-acmer/p/9852294.html
题解:
相关变量解释:
1 int n,m;
2 int a[maxn][20];//a[i][j] : 第i个开关对第j个灯的效果。
3 bool vis[R(10)];//vis[i] : 判断状态i是否被访问过
4 struct Node
5 {
6 int status;//状态
7 int minTimes;//来到当前状态按下开关的最小次数
8 Node(int a=0,int b=0):status(a),minTimes(b){}
9 };
10 queue<Node >myqueue;//用队列中的状态去解锁其他为解锁(访问)过的状态,并能保证被解锁的状态的minTimes最小
步骤:
(1):将Node( (1<<n)+1,0 ) 加入队列,因为初始等全是亮的,对应到二进制就是n个1,并且需要 0 次按下开关。
(2):从队头依次弹出元素,并用当前状态去解锁其他状态,并能保证被其解锁的状态的minTimes是最小的。
(3):重复(2)过程,直到找到 0 状态或队列为空
AC代码:
1 #include<iostream>
2 #include<cstdio>
3 #include<queue>
4 #include<cstring>
5 using namespace std;
6 #define mem(a,b) memset(a,b,sizeof(a))
7 #define R(x) (1<<x)
8 const int maxn=100+10;
9
10 int n,m;
11 int a[maxn][20];//a[i][j] : 第i个开关对第j个灯的效果。
12 bool vis[R(10)];//vis[i] : 判断状态i是否被访问过
13 struct Node
14 {
15 int status;//状态
16 int minTimes;//来到当前状态按下开关的最小次数
17 Node(int a=0,int b=0):status(a),minTimes(b){}
18 };
19 queue<Node >myqueue;//用队列中的状态去解锁其他为解锁(访问)过的状态,并能保证被解锁的状态的minTimes最小
20
21 int nextStatus(int nowStatus,int i)
22 {
23 int x=nowStatus;
24 for(int j=1;j <= n;++j)//从右往左一一对应
25 {
26 if(a[i][j] == 1 && (x>>(j-1)&1))//一定要注意判断x的第j为是否为1
27 x ^= (1<<(j-1));//^ : 相同为0,不同为1
28 else if(a[i][j] == -1)
29 x |= (1<<(j-1));
30 }
31 return x;
32 }
33 int updataQ(Node node)
34 {
35 for(int i=1;i <= m;++i)
36 {
37 int status=nextStatus(node.status,i);//找到当前状态node.status可以解锁的下一状态
38 if(!vis[status])//如果被访问过,那么其minTimes肯定要小于当前的minTimes+1
39 myqueue.push(Node(status,node.minTimes+1)),vis[status]=true;
40 if(status == 0)//判断被解锁的状态是否为0状态
41 return node.minTimes+1;
42 }
43 return 0;
44 }
45 int Solve()
46 {
47 mem(vis,false);
48 while(!myqueue.empty())
49 myqueue.pop();
50 myqueue.push(Node(R(n)-1,0));//步骤(1)
51 while(!myqueue.empty())//步骤(2)(3)
52 {
53 Node node=myqueue.front();
54 myqueue.pop();
55 int res=updataQ(node);//更新队列中的状态
56 if(res != 0)//判断被解锁的状态是否有0状态,如果有,直接输出,一定是最小的按下次数
57 return res;
58 }
59 return -1;
60 }
61 int main()
62 {
63 scanf("%d%d",&n,&m);
64 for(int i=1;i <= m;++i)
65 for(int j=n;j >= 1;--j)//j : n down 1 用意:与二进制的位数一一对应(从右往左)
66 scanf("%d",a[i]+j);
67 printf("%d\n",Solve());
68 }
来源:oschina
链接:https://my.oschina.net/u/4412687/blog/3742838