zoukankan      html  css  js  c++  java
  • [Luogu2622]关灯问题$||$(状压$DP$)

    #(color{red}{mathcal{Description}})

    (Link)

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

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

    #(color{red}{mathcal{Solution}})

    (emmmm)一开做这个题的时候是为了刷最短路水题的来着……结果发现好像需要状态压缩??等会儿,我都压完了还跑什么sb最短路啊,直接DP不就行了吗……我们发现这个题好像只要一维就行(你也找不出第二维啊),我们令(dp_i)表示到达状态(i)时所需要的最小步数,如果初始位置是全0状态,那么答案就是(dp_{(1 << n)-1})(即(n)个灯都是开着的状态)。

    然后就只要判断一下状态是否合法即可,转移时的状态转移方程就是$dp_{new} = min{dp_{last}+1} $

    (emmmm)至于最短路什么的还是日后再说吧(qwq)

    (Code)

    //pks学习专用 
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    
    using namespace std ;
    const int Inf = 1926081700 ;
    const int MAXN = 12, MAXM = 1025 ;
    int M, N, i, j, k, t, f[1 << MAXN], A[MAXM][MAXN] ;
    
    int main(){
    	cin >> N >> M ;
    	for(i = 1; i <= M; i ++)
    		for(j = 1; j <= N; j ++)
    			cin >> A[i][j] ; 
    	fill(f + 1, f + MAXM + 1, Inf) ;
    	for(i = 0; i < (1 << N); i ++)
    		for(k = 1; k <= M; k ++){
    			t = i ;
    			for(j = 0; j < N; j ++)
    				if((A[k][j + 1] == 1 && !(i & 1 << j))||
    				   (A[k][j + 1] == -1 && (i & 1 << j)))
    				t ^= (1 << j) ;
    			f[t] = min(f[t], f[i] + 1) ; 
    		}
    	if(f[(1 << N) - 1] == Inf) cout << "-1" << endl ;
    	else cout << f[(1 << N) - 1] << endl ;
    }
    
  • 相关阅读:
    Redis面试题 总结
    C++ 自由存储区是否等价于堆?(转)
    线程同步方式
    epoll的原理 (一)(转)
    C/C++ 中 volatile 关键字详解(转)
    Linux堆内存管理
    找出数组中出现次数超过一半的数
    剑指offer-复杂链表的复制
    已知二叉树前序中序遍历重建二叉树
    Linux常用命令
  • 原文地址:https://www.cnblogs.com/pks-t/p/9361614.html
Copyright © 2011-2022 走看看