【UVA12235 Help Bubu】

【Analysis】

可以发现书的高度的值域很小,肯定和状压有关;很容易想到

Dp[i][j]....表示前i本书中拿了j本的最小混乱值

现在再加一维

Dp[i][j][s]..表示前i本书中拿了j本,剩下的书的种类的集合的最小混乱值

注意这里的 s s s是种类的集合,而不是每本书的状态

我们考虑第 i i i本书是否要拿走,如果这本的前面没拿走的最后那本的高度和这本的相同,那么这本不需要那走,然而已有的状态表示不出对这个没拿走的最后一本的高度是多少,于是再加一维

Dp[i][j][s][k]表示前i本书中拿了j本,剩下的书的种类的集合,且最后一本没拿走的书的高度为k的最小混乱值

if (ai == k) Dp[i][j][s][ai] = std::min(Dp[i - 1][j][s][ai]);

//第i本不拿

else Dp[i][j][s|(1<<ai)][ai] = std::min(Dp[i - 1][j][s][k]), 
//第i本不拿
Dp[i][j + 1][s][k] = std::min(Dp[i - 1][j][s][k]);
//拿

注意这里加入时,一定是 S ∣ ( 1 &lt; &lt; h ) S|(1&lt;&lt;h) S(1<<h), 一定不能用异或

预处理完后还要把书放回去

for (int j = 0;j <= lim; ++j)
	for (int s = all; s; s = (s - 1) & all)
		for (int k = 0;k < 8; ++k)
		{
			if (Dp[d][j][s][k] == INF) continue;
			int cur = 0; 
    	  for (int tmp = all ^ s; tmp; tmp >>= 1) 
     	  if (tmp & 1) cur++;
         //这个地方cur表示把cur种书所有都拿出来了
         //如果有一种书还有一本没拿出来,那么可以贪心把书放在那一本旁边不影响结果
         //所以这里只讨论所有拿出来的书的种类对答案的影响
			ans = std::min(ans, Dp[d][j][s][k] + cur);
		}

还有一点优化, 可以发现 i i i只和 i − 1 i - 1 i1有关,可以滚动数组

【Code】

#include <cstdio>
#include <set>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <queue>
#include <map>

namespace IO
{
    inline char gc()
    {
        static char s[1<<20|1]={0},*p1=s,*p2=s;
        return (p1==p2)&&(p2=(p1=s)+fread(s,1,1<<20,stdin),p1==p2)?EOF:*(p1++);
    }
//	inline char gc() { return getchar(); }
	inline long long read()
	{
		long long ret=0;bool flag=0;char c=gc();
		while ((c<'0')|(c>'9')) flag ^= !(c^'-'),c=gc();
		while ((c>='0')&(c<='9')) ret=(ret<<1)+(ret<<3)+(c^'0'),c=gc();
		return flag?-ret:ret;
 	}
 	char OutputAns[1<<20|1],*OutputCur = OutputAns;
 	inline void output()
 	{
 		OutputCur -= fwrite(OutputAns,1,OutputCur - OutputAns,stdout);
	}
	inline void print(long long ans)
	{
		char s[20]={0};
		if (OutputCur - OutputAns + sprintf(s,"%lld",ans) >> 20) output();
		OutputCur += sprintf(OutputCur,"%lld",ans);
	}
	inline void printc(char c)
	{
		if (OutputCur - OutputAns + 1 >> 20) output();
		*(OutputCur++) = c;
	}
}

using IO::read;
using IO::print;
using IO::printc;
using IO::output;

template <class T> inline T max (T x, T y) { return x > y ? x : y; }

template <class T> inline T min(T x, T y) { return x < y ? x : y; }

const int M = 111;

const int INF = 0x3f3f3f3f;

int Dp[2][M][(1<<8) + 2][10];

int n, lim, ans, d, all, h, ca;

int main(void)
{
	while (n = read(), lim = read())
	{
		all = 0, ans = 1e9; memset(Dp[0], 0x3f, sizeof Dp[0]); d = 0;
		for (int i = 1;i <= n; ++i)
		{
			h = read() - 25, d ^= 1; memset(Dp[d], 0x3f, sizeof Dp[d]); Dp[d][i - 1][(1<<h)][h] = 1;
			for (int j = 0;j <= std::min(i, lim); ++j)
				for (int s = all; s; s = (s - 1) & all)
					for (int k = 0;k < 8; ++k)
					{
						if (Dp[d ^ 1][j][s][k] == INF) continue;
						if (h == k) Dp[d][j][s][h] = std::min(Dp[d][j][s][h], Dp[d ^ 1][j][s][h]);
						else 
						{
							Dp[d][j][s | (1<<h)][h] = std::min(Dp[d][j][s | (1<<h)][h], Dp[d ^ 1][j][s][k] + 1);
							Dp[d][j + 1][s][k] = std::min(Dp[d][j + 1][s][k], Dp[d ^ 1][j][s][k]);
						}
					}
			all |= (1<<h);
		}
		for (int j = 0;j <= lim; ++j)
			for (int s = all; s; s = (s - 1) & all)
				for (int k = 0;k < 8; ++k)
				{
					if (Dp[d][j][s][k] == INF) continue;
					int cur = 0; for (int tmp = all ^ s; tmp; tmp >>= 1) if (tmp & 1) cur++;
					ans = std::min(ans, Dp[d][j][s][k] + cur);
				} printf("Case %d: %d\n\n", ++ca, ans);
	} return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值