Help bubu

很有趣的一道dp题

我们先换个角度看这道题

我们可以把他看作,最多取出k,然后把一样的放一起,在放到一个地方去,使得答案最小

我们考虑dp

(f[i][j][o][la])表示第(i)本书,取了(j)本,然后没有取出的书种类状态(o),最后一个没有取出的为(la)的答案

那么就有状态转换方程

当前这本不取出

(f[i][j][o][la]=min:{f[i-1][j][o|(1<<a[i])][a[i]]+[a[i]!=la]})

否则

(f[i][j][o][la]=min:{f[i-1][j-1][o][la]+((ospace and space((1<<a[i])) orspace is[i][a[i]])?0:1)})

其中(is[i][j])表示位置(i)(j)为不为最后一个

#include<bits/stdc++.h>
#define N 511
#define K 111
#define M 9
using namespace std;
int n,k,a[N];
bool is[N][M];
int f[2][K][1<<M][M];
inline void work(int t){
	scanf("%d%d",&n,&k);
	if(!n&&!k)exit(0);
	memset(is,0,sizeof(is));
	int i,j,o,la;
	for(i=1;i<=n;++i){
		scanf("%d",&a[i]);
		a[i]-=25;
	}
	for(i=1;i<=n;++i)
	for(j=i+1;j<=n;++j)
	is[i][a[j]]=1;
	memset(f[0],63,sizeof(f[0]));
	f[0][0][0][8]=0;
	for(i=1;i<=n;++i){
		memset(f[i&1],63,sizeof(f[i&1]));
		for(j=0;j<=k;++j)
		for(o=0;o<(1<<8);++o)
		for(la=0;la<=8;++la)
		if(la==8||o&(1<<la)){
			f[i&1][j][o|(1<<a[i])][a[i]]=min(f[(i&1)^1][j][o][la]+(a[i]!=la),f[i&1][j][o|(1<<a[i])][a[i]]);
			if(j>=1)f[i&1][j][o][la]=min(f[i&1][j][o][la],f[(i&1)^1][j-1][o][la]+(((o&(1<<a[i]))||is[i][a[i]])?0:1));
		}
	}
	int ans(1e9);
	for(j=0;j<=k;++j)
	for(o=0;o<(1<<8);++o)
	for(la=0;la<=8;++la)if(la==8||o&(1<<la))ans=min(ans,f[n&1][j][o][la]);
	printf("Case %d: %d

",t,ans);
}
int main( ){
	int i;
	for(i=1;;++i)
	work(i);
}
原文地址:https://www.cnblogs.com/the-Blog-of-Mikasa/p/14006570.html