• 状压dp--洛谷P2622


    状压dp--洛谷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

    思路

    用二进制位1表示第j盏灯开的情况,0表示关的情况,bfs搜所有情况

    二进制的运算稍加思考易懂

    vis记录步数,这里由于初始为1,所以步数算多一步,答案输出为前一步的vis

    根据灯的所有状态,vis大小最大为2^n=1024

    #include <iostream>
    #include <algorithm>
    #include <string>
    #include <cstring>
    #include <cmath>
    #include <vector>
    #include <map>
    #include <set>
    #include <queue>
    #include <stack>
    #include <iomanip>
    #include <cstdio>
    
    using namespace std;
    typedef long long LL;
    typedef pair<double, double> PDD;
    typedef pair<LL, LL> PLL;
    
    const LL N = 1e5+7;
    const LL MOD = 1e9+7;
    const LL INF = 0x3f3f3f3f;
    
    #define lson l, m, rt>>1
    #define rson m+1, r, rt>>1|1
    
    int a[105][15], n, m, vis[N];
    void solve()
    {
        int now = (1<<n)-1, next;
        vis[now] = 1;
        queue<int> q;
        q.push(now);
        while(!q.empty())
        {
            now = q.front();q.pop();
            for(int i = 1;i <= m;++i)
            {
                next = now;
                for(int j = 1;j <= n;++j)
                {
                    if(a[i][j] == 1 && next&(1<<(j-1)))//将1变为0
                        next ^= 1<<(j-1);
                    else if(a[i][j] == -1)//将0变为1
                        next |= 1<<(j-1);
                }
                if(!next)
                {
                    cout << vis[now] << endl;
                    return ;
                }
                else if(!vis[next])
                {
                    vis[next] = vis[now]+1;
                    q.push(next);
                }
            }
        }
        puts("-1");
    }
    
    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]);
        solve();
        return 0;
    }
    
    
  • 相关阅读:
    shift and/or 算法
    FFT求解字符串匹配
    hdu 6981/ 2021“MINIEYE杯”中国大学生算法设计超级联赛(3)1009 Rise in Price(剪枝,dp合并)
    Rancher监控指标一文干到底(workload metrics)
    RocketMQ详解(二)启动运行原理
    新人如何快速剖析源码
    RocketMQ详解(三)核心设计原理(待完善)
    windows powershell下载文件的4种方式
    windows 调用bat脚本时pause处理
    python3 中的b''解析
  • 原文地址:https://www.cnblogs.com/shuizhidao/p/11268943.html
Copyright © 2020-2023  润新知