洛谷2622关灯问题II(状压+最短路)

题目链接:https://www.luogu.org/problem/P2622

题目描述

现有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

 

解题思路:用二进制表示每个灯的状态那么答案为dis【0】,到达某个状态考虑按下所有开关进行转移即可,如果dis【0】==inf输出-1即可。

#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
int dis[1500];
int mp[105][15];
queue<int> que;
int vis[1500];
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    memset(dis,0x3f,sizeof(dis));
    for(int i=0;i<m;i++){
        for(int j=0;j<n;j++){
            scanf("%d",&mp[i][j]);
        }
    }
    dis[(1<<n)-1]=0;
    que.push((1<<n)-1);
    vis[(1<<n)-1]=1;
    while(!que.empty()){
        int now=que.front();
        que.pop();
        vis[now]=0;
        for(int i=0;i<m;i++){
            int tem=now;
            for(int j=0;j<n;j++){
                if(mp[i][j]==-1){
                tem=tem|(1<<j);
                }
                else if(mp[i][j]==1){
                    tem=tem|(1<<j);
                    tem-=(1<<j);
                }
            }
            if(dis[tem]>dis[now]+1){
            dis[tem]=dis[now]+1;
            if(vis[tem]==0){
                que.push(tem);
                vis[tem]=1;
            }
        }
        }
        
    }
    printf("%d\n",dis[0]==inf?-1:dis[0]);
    return 0;
} 

 

posted @ 2019-09-03 13:38  风雨兼程-zhi  阅读(237)  评论(0编辑  收藏  举报