解题报告:洛谷 P2622 关灯问题Ⅱ

版权声明:转载请附带原文链接,请勿随意删除原文内容,允许少量格式和/或内容修改,谢谢! https://blog.csdn.net/weixin_37661548/article/details/87390933

题目链接

参考代码

#include <bits/stdc++.h>
using namespace std;

int n,m;
int effect[105][15],dp[1 << 12];

void init()
{
	scanf("%d%d",&n,&m);
	for (int i = 1; i <= m; ++i)
		for (int j = 1; j <= n; ++j)
			scanf("%d",&effect[i][j]);
	memset(dp,0x3f,sizeof(dp));
	dp[(1 << n) - 1] = 0;
}

void work()
{
	for (int s = (1 << n) - 1; s; --s)
	{
		for (int Switch = 1; Switch <= m; ++Switch)
		{
			int newState = s;
			for (int l = 1; l <= n; ++l)
			{
				switch (effect[Switch][l])
				{
					case 1 :
						{
							newState = newState & ~ (1 << (l - 1));
							break;
						}
					case -1 :
						{
							newState = newState | (1 << (l - 1));
							break;
						}
					default : break;
				}
			}
			dp[newState] = min(dp[newState],dp[s] + 1);
		}
	}
	printf("%d",dp[0] == 0x3f3f3f3f ? -1 : dp[0]);
}

int main()
{
	init();
	work();
	return 0;
}

分析

  • d p [ s ] dp[s] 为灯状态为 s s 时所需最少操作次数。
  • 显然, d p [ 0 ] dp[0] (全关)就是答案, d p [ ( 1 &lt; &lt; n ) 1 ] = 0 dp[(1 &lt;&lt; n) - 1] = 0 ,问最少,将 d p [ ] dp[] 初始化为极大值。
  • 枚举所有的状态,再枚举所有的开关 i i ,则 d p [ s s ] = m i n ( d p [ s s ] , d p [ s ] + 1 ) dp[ss] = min(dp[ss],dp[s] + 1) ,其中, s s ss 是状态 s s 经过按动开关 i i 后的状态,最坏需要开关数+1。
  • 如何根据状态 s s 推得状态 s s ss ?根据题意, a [ i ] a[i] 代表开关i控制灯的情况,对于状态 s s 和开关 i i ,枚举所有的灯 l l ,取末 l l 位,得到该灯的状态,进行操作即可。
  • 注意:假设有n件“物品”,“全选”代表的状态为 ( 1 &lt; &lt; n ) 1 (1 &lt;&lt; n) - 1 ,不要忘了 1 -1

猜你喜欢

转载自blog.csdn.net/weixin_37661548/article/details/87390933
今日推荐