【洛谷P2622】關燈問題II【BFS】【狀壓】
阿新 • • 發佈:2018-11-09
題目大意:
題目連結:https://www.luogu.org/problemnew/show/P2622
有
個開關和
盞燈,第
個開關要麼可以開啟第
盞燈,要麼可以關上第
盞燈,要麼不對第
盞燈起作用。求把
盞燈全部開啟的最少步數。
思路:
這道題很明顯可以用
做。因為對於每一種情況,我們也就只有
種轉移方法,而求的是最優解。
而最多隻有10盞燈,所以可以想到用狀壓。這樣每種情況就被壓縮成了
~
中的一個數。
那麼搜就好了。
注意細節。
程式碼:
#include <cstdio>
#include <queue>
using namespace std;
int n,m,a[101][11];
bool p[1024];
int change(int x,int y) //轉換
{
for (int i=1;i<=n;i++)
{
if (a[y][i]==1) x|=(1<<(n-i));
//如果這個開關可以開啟這盞燈,那麼就直接或,因為1 or 1=0 or 1=1
if (a[y][i]==-1&&(x&(1<<(n-i)))) x^=(1<<(n-i));
//如果這個開關可以關上這盞燈,那麼就要判斷這一位是不是1,如果是1才異或。
}
return x;
}
void bfs()
{
queue<int> dis; //最小步數
queue<int> q; //狀態(已壓縮)
q.push(0);
dis.push(0);
while (q.size())
{
int u=q.front();
int d=dis.front();
q.pop();
dis.pop();
for (int i=1;i<=m;i++) //美劇每一個開關
{
int v=change(u,i);
if (p[v]) continue; //判重
p[v]=1;
q.push(v);
dis.push(d+1);
if (v==(1<<n)-1) //全部開啟
{
printf("%d\n",d+1);
return;
}
}
}
printf("-1");
return;
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
for (int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
bfs();
return 0;
}