洛谷 P2622 关灯问题II (状态压缩+BFS)

题目描述
现有n盏灯,以及m个按钮。每个按钮可以同时控制这n盏灯——按下了第i个按钮,对于所有的灯都有一个效果。按下i按钮对于第j盏灯,是下面3中效果之一:如果a[i][j]为1,那么当这盏灯开了的时候,把它关上,否则不管;如果为-1的话,如果这盏灯是关的,那么把它打开,否则也不管;如果是0,无论这灯是否开,都不管。

现在这些灯都是开的,给出所有开关对所有灯的控制效果,求问最少要按几下按钮才能全部关掉。

输入输出格式
输入格式:
前两行两个数,n m

接下来m行,每行n个数,a[i][j]表示第i个开关对第j个灯的效果。

输出格式:
一个整数,表示最少按按钮次数。如果没有任何办法使其全部关闭,输出-1

输入输出样例
输入样例#1:
3
2
1 0 1
-1 1 0
输出样例#1:
2
说明
对于20%数据,输出无解可以得分。

对于20%数据,n<=5

对于20%数据,m<=20

上面的数据点可能会重叠。

对于100%数据 n<=10,m<=100

题意:

思路:

用一个int类型的整数state 来记录当前灯泡的状态, 二进制来描述信息
state 的第i位为1,表示第i个灯泡现在是亮的,否则是灭掉的。
然后暴力去跑BFS, 同时用一个数组VIS标记哪些状态被访问了,而利用bfs的性质,后面一个状态state,如果 vis[state] =1 表明在前面被访问过了,那么这一个就可以忽略了,因为前面的步数step一定小于等于当前的step.

细节见代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#define ALL(x) (x).begin(), (x).end()
#define rt return
#define dll(x) scanf("%I64d",&x)
#define xll(x) printf("%I64d
",x)
#define sz(a) int(a.size())
#define all(a) a.begin(), a.end()
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define gg(x) getInt(&x)
#define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
using namespace std;
typedef long long ll;
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
ll powmod(ll a,ll b,ll MOD){ll ans=1;while(b){if(b%2)ans=ans*a%MOD;a=a*a%MOD;b/=2;}return ans;}
inline void getInt(int* p);
const int maxn=1000010;
const int inf=0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
int n,m;
bool flag=1;
int a[105][105];
int ans=inf;
struct node
{
    int state;
    int step;
    node(){}
    node(int st,int sstep)
    {
        state=st;
        step=sstep;
    }
};
queue<node> q;
int vis[2500];
void bfs()
{
    int num=0;
    for(int i=1;i<=n;i++)
    {
        num|=(1<<i);
    }
    q.push(node(num,0));
    node temp;
    int cnt=0;
    while(flag&&!q.empty())
    {
        temp=q.front();
        q.pop();
        cnt++;
        if(temp.state==0)
        {
            ans=min(ans,temp.step);
            flag=0;
            break;
        }
        for(int i=1;i<=m;i++)
        {
            num=temp.state;
            for(int j=1;j<=n;j++)
            {
                if (a[i][j]==1)
                {
                    if((num&(1<<j))>0)
                    {
                        num-=(1<<j);
                    }
                }else if(a[i][j]==-1)
                {
                    if((num&(1<<j))==0)
                    {
                        num+=(1<<j);
                    }
                }
            }
            if(!vis[num])
            {
                q.push(node(num,temp.step+1));
                vis[num]=1;
            }
        }
    }

}
int main()
{
    // freopen("D:\common_text\code_stream\in.txt","r",stdin);
    //freopen("D:common_textcode_streamout.txt","w",stdout);
    gbtb;
    // cout<<(1<<10)<<endl;
    cin>>n>>m;
    repd(i,1,m)
    {
        repd(j,1,n)
        {
            cin>>a[i][j];
        }
    }
    bfs();
    if(ans==inf)
    {
        ans=-1;
    }
    cout<<ans<<endl;
    
    
    return 0;
}

inline void getInt(int* p) {
    char ch;
    do {
        ch = getchar();
    } while (ch == ' ' || ch == '
');
    if (ch == '-') {
        *p = -(getchar() - '0');
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 - ch + '0';
        }
    }
    else {
        *p = ch - '0';
        while ((ch = getchar()) >= '0' && ch <= '9') {
            *p = *p * 10 + ch - '0';
        }
    }
}




本博客为本人原创,如需转载,请必须声明博客的源地址。 本人博客地址为:www.cnblogs.com/qieqiemin/ 希望所写的文章对您有帮助。
原文地址:https://www.cnblogs.com/qieqiemin/p/11146645.html