题目描述
某公司运进一批箱子,总数为N(1≤N≤1000)由“传送带”依次运入,然后在仓库内至多排成P(1≤P≤4)列,(如图8所示)。
![]()
现已知运来的箱子最多为M(1≤M≤20)种,想把同一种类的箱子尽量排在一起,以便美观。“美观程度”T定义为:T=∑(每列依次看到的不同种类数);所谓“依次看到的不同种类数”即为:如果某一列中第K个箱子与第K-1个箱子种类不同,则“美观程度”的值加1。求一种调动安排,使各列的“美观程度”值的和最小。(只输出最小值)
中国好样例
输入:
30 10 4
1 1 8 2 3 7 3 2 4 4 1 5 1 8 1 3 9 4 7 3 7 8 7 3 2 3 5 3 8 3
输出:
12
最优子结构很明显,动龟(动态规划)!初始想法:用f[i]表示前i个箱子所能获得的最小美观程度,分析后发现无法写出状态转移方程(这是有后效性的节奏啊)……再次分析可以得出:把当前箱子不论放在哪一列仅与当前栈顶(第一个)元素有关,所以用
OK,到这里,时间和空间就都能承受了,我也已经无力再去优化了。
(注:我码力太弱,上TA大神的代码)
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define S 21
int f[2][194485],p,now,pre=1,mi[5],m,a;
void dfs(int x,int state){
if(x<0){
if(f[pre][state]<1000){
int i;
for(i=p;i--;){
x=state%mi[i+1]/mi[i]; //取第i个栈顶元素
f[now][state+(a-x)*mi[i]]=min(f[now][state+(a-x)*mi[i]],f[pre][state]+(x!=a)); //状态转移
}
}
return;
}
for(int i=m;~i;--i)dfs(x-1,state*(m+1)+i);
}
int main(){
int n,i;
scanf("%d%d%d",&n,&m,&p);
mi[0]=1;
for(i=1;i<5;++i)mi[i]=mi[i-1]*(m+1);//幂
memset(f,127,sizeof(f));
f[0][0]=0;
while(n--){
scanf("%d",&a);
swap(now,pre);//滚动数组
memset(f[now],127,sizeof(f[now]));
dfs(p,0);
}
printf("%d\n",*min_element(f[now],f[now+1])); //取容器中最小值
}