LA 4490 Help Bubu (状压DP)

题意:给出n和k,表明书架上有n本书,可以取出k次书,每次取出后可以任意放回书架中,书的编号为25~32八种,定义该书架的混乱程度为片段的个数。求出最小的混乱度。


分析:看到题完全没什么头绪的样子,看了题解,这种略为复杂的状压DP的状态表示比起平时做DP题直接找一个切入点去建模YY状态的表示方法和状态转移方程,更像是直接对暴力搜索进行抽象后的得到的一个可行的状态表示方法,DP之所以效率高就是因为它的状态表示对问题进行了极大的抽象,把大部分中间情况压入了一个状态当中,然后利用无后效性逐步递推得到每种状态的结果。f[i][j][s][end]表示当前处理到了第i本书,前边一共拿走了j本,剩下的书的状态为s,最后一本书为end的最小混乱度,本题还有很重要的一点就是,我们拿走一本书后可以先不考虑放回,最后全部拿完后再一次全部放回,然后是对于每个本书i的策略:如果i和end同种,那么f[i][j][s][end] = f[i-1][j][s][end],否则拿走:f[i][j+1][s][end] = f[i-1][j][s][end]+1,不拿走f[i][j][s | col[i]][col[i]] = f[i-1][j][s][end]+1,边界条件f[0][0][0][0] = 0;

#include <queue>    
#include <vector>    
#include <cstdio>    
#include <utility>    
#include <cstring>    
#include <iostream>    
#include <algorithm>    
#define INF 0x3f3f3f3f
using namespace std;  
int n,k,tot,toss,f[2][105][300][10],col[105];
int got(int x)
{
	int now = x ^ tot,num = 0;
	while(now)
	{
		if(now & 1)  num++;
		now>>=1;
	} 
	return num;
}  
int	main()
{
	cin.sync_with_stdio(false);
	while(cin>>n>>k && n+k)
	{
		tot = 0;
		for(int i = 1;i <= n;i++) 
		{	
			cin>>col[i];
			col[i]-=24;
			tot = tot | (1<<(col[i]-1));
		}
		memset(f[0],INF,sizeof(f[0]));
		f[0][0][0][0] = 0;
		for(int i = 0;i < n;i++)
		{
			int now = i & 1;
			memset(f[now^1],INF,sizeof(f[now^1]));
			for(int j = 0;j <= k;j++)
		 	 for(int s = tot;s >= 0;s = min(s-1,(s-1)&tot))
		      for(int End = 0;End <= 8;End++)
		  	  {
				 if(col[i+1] == End) f[now^1][j][s][End] = min(f[now^1][j][s][End],f[now][j][s][End]);
				 else
				 {
					 f[now^1][j+1][s][End] = min(f[now^1][j+1][s][End],f[now][j][s][End]);
					 f[now^1][j][s | (1<<(col[i+1]-1))][col[i+1]] = min(f[now^1][j][s | (1<<(col[i+1]-1))][col[i+1]],f[now][j][s][End]+1);	
				 }
		      }
		}
		int ans = 2147483647;
		for(int j = 0;j <= k;j++)
		 for(int s = tot;s >= 0;s = min(s-1,(s-1)&tot))
		  for(int End = 0;End <= 8;End++)
		   ans = min(ans,f[n & 1][j][s][End] + got(s));
		cout<<"Case "<<++toss<<": "<<ans<<endl<<endl;
	}	 
}  



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值