luogu 2622 关灯问题II

题目大意:

有一些灯,有些开关可以控制这些灯,给出矩阵表示控制

对于矩阵中的a i j 表示第i个开关控制第j个灯的情况

若元素为1 表示当灯开着的时候,关掉灯

若元素为0 表示无操作

若元素为-1 表示当灯关着的时候,打开灯

思路:

因为灯的数量很小

我们可以将所有灯的状态用二进制来表示

然后我们跑一下所有状态的spfa

位运算记错了毁一生:

| 或 有一个是1就为1

^ 异或 不一样就为1 

& 与 两个都是1才为1

~(1<<j) 表示除了第j位全部为1

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<queue>
 8 #include<vector>
 9 #include<set>
10 #include<stack>
11 #define inf 2147483647
12 #define ll long long
13 #define MOD 1000000000
14 #define MAXN 22
15 using namespace std;
16 inline int read()
17 {
18     int x=0,f=1;
19     char ch=getchar();
20     while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
21     while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
22     return x*f;
23 }
24 int n,m,dis[MAXN*100],cnt;
25 bool vis[MAXN*100];
26 short map[MAXN*5][MAXN];
27 int spfa()
28 {
29     queue <int> q;
30     int tmp;
31     q.push(cnt);vis[cnt]=1;
32     dis[cnt]=0;
33     while(!q.empty())
34     {
35         int k=q.front();
36         q.pop();
37         for(int i=1;i<=m;i++)
38         {
39             tmp=k;
40             for(int j=0;j<n;j++)
41             {
42                 if(map[i][j]==1) tmp=tmp&(~(1<<j));
43                 if(map[i][j]==-1) tmp=tmp|(1<<j);
44             }
45             if(dis[tmp]>dis[k]+1) 
46             {
47                 dis[tmp]=dis[k]+1;
48                 if(!vis[tmp]) {vis[tmp]=1;q.push(tmp);}
49             }
50         }
51         vis[k]=0;
52     }
53     if(dis[0]>=2*MOD) return -1;
54     return dis[0];
55 }
56 int main()
57 {
58     n=read(),m=read();
59     for(int i=1;i<=m;i++)
60         for(int j=0;j<n;j++) map[i][j]=read();
61     memset(dis,127,sizeof(dis));
62     cnt=(1<<n)-1;
63     printf("%d",spfa()); 
64 }
View Code
原文地址:https://www.cnblogs.com/yyc-jack-0920/p/7682076.html