小小注解:
1.
vis:表示到達該狀態的步數(min)+1,?
因為我們是從開始狀態 窮舉,所以每次到一個新狀態(之前沒有到過的狀態)就是最小步數。
如何判斷是否是一個新狀態呢,vis 知道,如果是新狀態?vis=0;
另外,把開始狀態設置為1,設置為 0 的話,程序就會把開始狀態當作一個新狀態,而開始狀態當然不是一個新狀態。
11.
開: 初始:1 0 1 0? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?關: 初始:1 0 1 0
? ? ? ? ? ?開:?1 1 0 0? ? ?(|)? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? 關:?1 1 0 0
? ? ??? 結果:?1 1 1 0? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??結果: 0 0 1 0
? ? ? ? ?初始 |?開 = 結果? ? ? ? ? ? ?? ? ? ? ? ? ? ? ? ? ? ? ?~關: 0 0 1 1? ? ?(&)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?初始 &(~?關)?= 結果?
111.
開始狀態的得到:
例: n=4時;開始狀態:1 1 1 1,即 (1<<n)-1 ;
注意:括號不能省,以為 1<<n-1 = 1<<(n-1);
#include<iostream>
#include<queue>
using namespace std;
int a[3300],b[3300]; //開燈 關燈 一個操作拆成兩個 分別存在 a b中
int vis[3300]; //到達該狀態的步數+1;
//對于一種狀態 1改燈開 0關
int main(){int n,m; cin>>n>>m;for(int i=0;i<m;i++)for(int j=0;j<n;j++){int x; scanf("%d",&x);a[i]<<=1; b[i]<<=1;if(x==1) b[i]++;if(x==-1) a[i]++; }queue<int>q;q.push((1<<n)-1);vis[(1<<n)-1]=1;while(q.size()){int num=q.front(); q.pop();for(int i=0;i<m;i++){int temp=num|a[i];temp=temp&(~b[i]);if(vis[temp]) continue;vis[temp]=vis[num]+1; q.push(temp);if(temp==0){printf("%d",vis[0]-1); return 0;}}}printf("-1");return 0;
}