UVA12235 Help Bubu 题解

2021/12/6 23:22:36

本文主要是介绍UVA12235 Help Bubu 题解,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

题目链接

题目

Bubu’s bookshelf is in a mess! Help him!
There are nbooks on his bookshelf. We define the mess value to be the number of segments of
consecutive equal-height books. For example, if the book heights are 30, 30, 31, 31, 32, the mess
value is 3, that of 30, 32, 32, 31 is also 3, but the mess value of 31, 32, 31, 32, 31 is 5 — it’s indeed in
a mess!
Bubu wants to reduce the mess value as much as possible, but he’s a little bit tired, so he decided
to take out at most kbooks, then put them back somewhere in the shelf. Could you help him?

书架上有 N 本书,书本高度是 [25cm,32cm],凌乱地排着。
定义一排书的整齐度是指最少可以被划分成高度连续相等的书的段数
比如 {30,32,32,31} 整齐度是 3。
比如 {31,32,31,32,31} 整齐度是 5。
现在最多从其中拿出 K 本书,然后塞回去。
问整理后,最少可以有多少段高度相等的连续区间。

K <= N <= 100

思路

发现书本高度最大最小差为8,很容易想到状压dp。

设 \(dp(i, j, k, o)\) 表示前 \(i\) 本书里拿出 \(j\) 本,剩下书高度集合为 \(k\),且最后一本书高度为 \(o\) 的最小凌乱度。

然后枚举每一本书拿或者不拿。

如果不拿,则 \(k\) 变成 \(k|(1<<a_i)\),代表这本书放入未被拿的集合。\(o\) 变成 \(a_i\)。如果之前 \(o\neq a_i\),则要加1。

如果拿,剩下书的集合还有最后一本不变。然后我们考虑是否+1,如果为拿出的集合中有这本书,我们可以把现在这本书插到它旁边,然后不用+1。如果后面还有和它一样的书,我们就把现在这本书的命运交给后面那本书。除了这两种情况,其它都要+1。

可能会MLE,要滚动数组优化。

Code

// Problem: UVA12235 Help Bubu
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/UVA12235
// Memory Limit: 0 MB
// Time Limit: 3000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;
//#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
//#define M
//#define mo
#define N 110
int n, m, i, j, k; 
int ans, dp[2][N][300][10]; 
int is[1010][10], a[1010]; 
int o, nw, ls, K, t; 

void minn(int &x, int y)
{
	x=min(x, y); 
}

signed main()
{
//	freopen("tiaoshi.in", "r", stdin); 
//	freopen("tiaoshi.out", "w", stdout); 
	scanf("%d%d", &n, &K);
	while(n)
	{
		memset(dp, 0x3f, sizeof(dp)); 
		memset(is, 0, sizeof(is)); 
		for(i=1; i<=n; ++i) a[i]=read()-25; 
		// for(i=1; i<=n; ++i) printf("%d ", a[i]);  
		// printf("\n"); 
		for(i=1; i<=n; ++i)
			for(j=i+1; j<=n; ++j)
				is[i][a[j]]=1; 
		ans=dp[0][0][0][0]; 
		dp[0][0][0][8]=0; 
		for(i=1; i<=n; ++i)
		{
			nw=i&1; ls=(!nw); 
			memset(dp[nw], 0x3f, sizeof(dp[nw])); 
			for(j=0; j<=K; ++j)
				for(k=0; k<=255; ++k)
					for(o=0; o<=8; ++o)
						if(o==8||((1<<o)&k))//之前未选集合中含有最后一个
						{
							minn(dp[nw][j][k|(1<<a[i])][a[i]], dp[ls][j][k][o]+(a[i]!=o)); 
							if(j) minn(dp[nw][j][k][o], dp[ls][j-1][k][o]+( (((1<<a[i])&k)||(is[i][a[i]])) ? 0 : 1 ) ); 
						}
		}
		for(j=0; j<=K; ++j)
			for(k=0; k<=255; ++k)
				for(o=0; o<=8; ++o)
					if(o==8||((1<<o)&k)) 
						ans=min(ans, dp[n&1][j][k][o]); 
		printf("Case %d: %d\n\n", ++t, ans); 
		scanf("%d%d", &n, &K);
	}
	return 0; 
}



这篇关于UVA12235 Help Bubu 题解的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程