1. 程式人生 > >P2622 關燈問題II (狀態壓縮入門)

P2622 關燈問題II (狀態壓縮入門)

題目連結: https://www.luogu.org/problemnew/show/P2622

具體思路:暴力,嘗試每個開關,然後看所有的情況中存不存在燈全部關閉的情況,在儲存所有燈的情況的時候,觀察到n的值不大,所以可以考慮用二進位制進行儲存,如果說這個數用二進位制表示的時候,如果第i位是1,代表第(i+1)個燈當前的狀態是開著的,否則就是關閉的.

AC程式碼:

#include<iostream>
#include<cstring>
#include<iomanip>
#include<algorithm>
#include<queue>
#include<stdio.h>
#include<cmath>
using namespace std;
# define inf 0x3f3f3f3f
# define ll long long
# define pi acos(-1.0)
const int mod = 1e9 ;
const int maxn = 200+100;
struct node
{
    int num;
    int step;
    node() {}
    node(int xx,int yy)
    {
        num=xx;
        step=yy;
    }
};
int a[maxn][maxn];
int vis[6000],n,m;
int bfs(int tot)
{
    queue<node>q;
    vis[tot]=1;
    q.push(node(tot,0));
    while(!q.empty())
    {
        node top=q.front();
        q.pop();
        int t=top.num;
        for(int i=1; i<=n; i++)
        {
            int tmp=t;
            for(int j=1; j<=m; j++)
            {
                if(a[i][j]==1)
                {
                    if(tmp&(1<<(j-1)))//如果說當前的燈是開著的,就改成關閉
                        tmp=tmp^(1<<(j-1));
                }
                if(a[i][j]==-1)
                {
                    tmp=tmp|(1<<(j-1));//改成開啟的狀態
                }
            }
            if(vis[tmp])continue;
            vis[tmp]=1;
            q.push(node(tmp,top.step+1));
            if(tmp==0)
            {
                return top.step+1;
            }
        }
    }
    return -1;
}
int main()
{
    scanf("%d%d",&m,&n);
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=m; j++)
        {
            scanf("%d",&a[i][j]);
        }
    }
    int tmp=(1<<m)-1;//初始狀態,每一位上都是1
    int ans=bfs(tmp);
    printf("%d\n",ans);
    return 0;
}