zoukankan      html  css  js  c++  java
  • 洛谷 P3694 邦邦的大合唱站队 状压DP

    题目描述

    输入输出样例

    输入 #1 复制

    12 4
    1
    3
    2
    4
    2
    1
    2
    3
    1
    1
    3
    4

    输出 #1 复制

    7

    说明/提示

    分析

    首先要注意合唱队排好队之后不一定是按(1.2.3......m)的顺序的
    (N)的范围很大,但(m)的数据比较小,所以我们考虑装压DP
    我们设(f[i])为状态为(i)的合唱队已经安排好位置的最小花费
    接下来就是状态转移方程的问题

    for(int i=1;i<(1<<m);i++){
            int len=0;
            for(int j=1;j<=m;j++){
                if(i&(1<<(j-1))) len+=num[j];
            }
            for(int j=1;j<=m;j++){
                if(i&(1<<(j-1))) f[i]=min(f[i],f[i^(1<<(j-1))]+num[j]-sum[len][j]+sum[len-num[j]][j]);
            }
        }
    

    第一维枚举的是状态,在枚举状态之后,我们还要统计当前状态下哪些合唱队已经排好了位置
    我们用一个变量(len)记录排好队的总人数,如果当前合唱队已经排好了队,那么我们把总人数加上当前合唱队的人数
    其中,编号为(j)的合唱队的总人数(num[j])可以预处理
    为什么这样做呢?
    因为我们无论让偶像们怎么出队,他们最终的状态是确定的,肯定是一个合唱队的偶像站到一起,因此我们就可以统计排好队后当前区间的总长度
    接下来就是状态转移
    如果编号为(j)的合唱队在我们决策的范围之内,那我们就需要尝试将编号为(j)的合唱队的全体成员都放在队伍最后
    那么此时我们就需要将编号为(j)的合唱队中不在区间([len-num[j]+1,num[j]])的偶像移到该区间
    此时的花费为(num[j]-sum[len][j]+sum[len-num[j]][j])
    其中(sum[i][j])表示开始时前(i)个位置中编号为(j)的合唱队员的个数
    问题就可以解决了

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=22,maxm=1e5+5;
    int f[1<<maxn];
    int num[maxn],sum[maxm][maxn];
    int main(){
        int n,m;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            int aa;
            scanf("%d",&aa);
            num[aa]++;
            for(int j=1;j<=m;j++) sum[i][j]=sum[i-1][j];
            sum[i][aa]++;
        }
        memset(f,0x3f,sizeof(f));
        f[0]=0;
        for(int i=1;i<(1<<m);i++){
            int len=0;
            for(int j=1;j<=m;j++){
                if(i&(1<<(j-1))) len+=num[j];
            }
            for(int j=1;j<=m;j++){
                if(i&(1<<(j-1))) f[i]=min(f[i],f[i^(1<<(j-1))]+num[j]-sum[len][j]+sum[len-num[j]][j]);
            }
        }
        printf("%d
    ",f[(1<< m)-1]);
        return 0;
    }
    
  • 相关阅读:
    strlen和sizeof
    函数值传递和地址传递
    指向函数的指针变量
    for循环scanf赋值刷新缓冲区
    指针
    排序简化
    随机数找到最大值
    上楼梯问题
    分布式系统并发情况下会生成多个token
    Swagger 文档生成工具
  • 原文地址:https://www.cnblogs.com/liuchanglc/p/13197200.html
Copyright © 2011-2022 走看看