您的位置:首页 > 其它

最小美观程度

2015-08-29 00:06 246 查看
题目描述

某公司运进一批箱子,总数为N(1≤N≤1000)由“传送带”依次运入,然后在仓库内至多排成P(1≤P≤4)列,(如图8所示)。





现已知运来的箱子最多为M(1≤M≤20)种,想把同一种类的箱子尽量排在一起,以便美观。“美观程度”T定义为:T=∑\sum(每列依次看到的不同种类数);所谓“依次看到的不同种类数”即为:如果某一列中第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]f[i]表示前ii个箱子所能获得的最小美观程度,分析后发现无法写出状态转移方程(这是有后效性的节奏啊)……再次分析可以得出:把当前箱子不论放在哪一列仅与当前栈顶(第一个)元素有关,所以用f[i][a1][a2][a3][a4]f[i][a1][a2][a3][a4](PP最大为44)来表示前ii个箱子,当栈顶元素分别为a1、a2、a3、a4a1、a2、a3、a4时的最小美观程度,用前面的结果去更新后面的结果,貌似可以,终于没有后效性了,但仔细一想,卧槽,时间和空间复杂度……再来,很明显,栈顶元素分别为4、6、8、24、6、8、2其实与8、4、2、68、4、2、6是一样的(列与列之间没有差别),这样就可以把全排列优化为1种情况,一个很不错的进步,但是编程复杂度的问题……再来,撞鸭(状态压缩)!由于a1、a2、a3、a4a1、a2、a3、a4最大是MM,显然我们可以用一个M+1M+1进制的数字xx来同时记录a1、a2、a3、a4a1、a2、a3、a4,最大约为10510^5级别的,加上第一维的NN了以后貌似还不够明显……再来,再一分析可以发现,f[i]f[i]只与f[i−1]f[i-1]有关,这是用滚动数组的节奏啊。

OK,到这里,时间和空间就都能承受了,我也已经无力再去优化了。

(注:我码力太弱,上TA大神的代码)

[code]#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])); //取容器中最小值
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: