【洛谷 P2622】关灯问题II【状压DP】

题目描述

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

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

输入格式

前两行两个数, n m n m nm

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

输出格式

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

输入输出样例

输入 #1

3
2
1 0 1
-1 1 0

输出 #1

2

分析:

状压 D P DP DP( z h e n zhen zhen)( d e de de)( e e e)( x i n xin xin) ! ! ! ! !!!!
看到你谷 B F S BFS BFS解法的 我只能 %%% 谁让蒟蒻的我只能用状压 D P DP DP呢?
n , m n,m nm都很小 就考虑状压 D P DP DP f [ i ] f[i] f[i]表示灯到 i i i状态最少步数
枚举 0 0 0 1 1 1 − 1 -1 1三种状态 用一个变量 x x x累加步数 然后 D P : DP: DP
f [ x ] = m i n ( f [ x ] , f [ i ] + 1 ) f[x]=min(f[x],f[i]+1) f[x]=min(f[x],f[i]+1)

CODE:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,a[1005][15],f[2049]; 
int main(){
    
    
	scanf("%d%d",&n,&m);
	memset(f,0x3f,sizeof(f));
	for(int i=1;i<=m;i++)
		for(int j=1;j<=n;j++)
			scanf("%d",&a[i][j]);
	f[0]=0;
	for(int i=0;i<=(1<<n)-1;i++)  //枚举 1(1<<n)-1为二进制转换成十进制状态
		for(int j=1;j<=m;j++)
		{
    
    
			int qaq=i;
			for(int qwq=0;qwq<n;qwq++)
			{
    
    
				if(a[j][qwq+1]==0) continue;  //优化  0就不用做
				if(a[j][qwq+1]==-1&&(i&1<<qwq)||a[j][qwq+1]==1&&!(i&1<<qwq))  //其他两种状态
					qaq^=(1<<(qwq));  //累加
			} 
			f[qaq]=min(f[qaq],f[i]+1);   //DP
		}
		printf("%d",f[(1<<n)-1]==0x3f3f3f3f?-1:f[(1<<n)-1]);  //三目压行
	return 0;
}

猜你喜欢

转载自blog.csdn.net/dgssl_xhy/article/details/108126216
今日推荐