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

    【洛谷P3694】 邦邦的大合唱站队

    题目背景

    BanG Dream!里的所有偶像乐队要一起大合唱,不过在排队上出了一些问题。

    题目描述

    N个偶像排成一列,他们来自M个不同的乐队。每个团队至少有一个偶像。

    现在要求重新安排队列,使来自同一乐队的偶像连续的站在一起。重新安排的办法是,让若干偶像出列(剩下的偶像不动),然后让出列的偶像一个个归队到原来的空位,归队的位置任意。

    请问最少让多少偶像出列?

    输入输出格式

    输入格式:

    第一行2个整数N,M。

    接下来N个行,每行一个整数(a_i (1le a_i le M)),表示队列中第i个偶像的团队编号。

    输出格式:

    一个整数,表示答案

    一开始看这个题真的没有思路,想了一下直接写了个爆搜,枚举每个团队的开头位置在求答案取最小。

    真的意外可以过70分。

    暴搜

    code:

    #include<iostream>
    #include<cstdio>
    using namespace std;
    const int wx=201007;
    int tot[wx],sum[wx][17],vis[wx],pre[wx],last[wx],E[wx];
    inline int read(){
    	int sum=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
    	return sum*f;
    }
    int n,m,x;
    int ans=0x3f3f3f3f;
    void dfs(int now,int end,int num){
    	if(now==m+1&&end==n){
    		ans=min(ans,num);
    		return ;
    	}
    	if(num>=ans)return;
    	for(int i=1;i<=m;i++){
    		if(vis[i])continue;
    		vis[i]=1;
    		dfs(now+1,end+tot[i],tot[i]-sum[end+tot[i]][i]+sum[end][i]+num);
    		vis[i]=0;
    	}
    }
    signed main(){
    	n=read();m=read();
    	for(int i=1;i<=n;i++){
    		x=read();
    		for(int j=1;j<=m;j++)sum[i][j]=sum[i-1][j];
    		sum[i][x]=sum[i-1][x]+1;
    		tot[x]++;
    	}
    	dfs(1,0,0);
    	printf("%d
    ",ans);
    	return 0;
    }
    

    正解知道是状压,但是连状态都不会设(菜死了菜死了。。。)

    看了大佬博客才发现这题设了状态就完事了。。。

    (f(i))表示当前状态下的最优答案。因为数据范围,肯定是要状压m,怎么压是个问题。

    其实我们用二进制的一位表示一个团队,那么1代表这个团队已经站好了,0表示还没有站好。

    这里的站好定义要明确,就是这个团队里的每个人都紧挨着了,并且我们默认这些团队都是从头开始向后紧挨着的,(每一次取min保证之前的状态站法是最优的)。

    转移就比较好想了。

    [f(i)=f(i ^ (1<<j-1))+tot(j)-(sum(pos+tot(j))(j)-sum(pos)(j)) ]

    pos就是当前不算第i个团队的人的最后位置,枚举一边就可以了。

    复杂度(O(m*2^m))

    DP

    code:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    const int wx=100017;
    inline int read(){
    	int sum=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=(sum<<1)+(sum<<3)+ch-'0';ch=getchar();}
    	return sum*f;
    }
    int n,m;
    int f[1<<20],sum[wx][21],tot[21];
    int main(){
    	n=read();m=read();
    	for(int i=1;i<=n;i++){
    		int x;
    		x=read();
    		for(int j=1;j<=m;j++)sum[i][j]=sum[i-1][j];
    		sum[i][x]=sum[i][x]+1;
    		tot[x]++;	
    	}
    	memset(f,0x3f,sizeof f);
    	f[0]=0;int WX=(1<<m);
    	for(int i=1;i<WX;i++){
    		int pos=0;
    		for(int j=1;j<=m;j++){
    			if(i&(1<<j-1)){
    				pos+=tot[j];
    			}
    		}
    		for(int j=1;j<=m;j++){
    			if(i&(1<<j-1)){
    				f[i]=min(f[i],f[i^(1<<j-1)]+tot[j]+sum[pos-tot[j]][j]-sum[pos][j]);
    			}
    		}
    	}
    	printf("%d
    ",f[WX-1]);
    	return 0;
    }
    
  • 相关阅读:
    sitemap.xml
    Java--调试--单步调试,断言,单元测试
    同时显示多个 Notification
    HttpURLConnection请求数据流的写入(write)和读取(read)
    Spring jdbc 对象Mapper的简单封装
    mongodb之java CRUD 简单操作
    第三章 AOP 基于@AspectJ的AOP
    从源码角度深入分析log4j配置文件使用
    log4j.properties文件配置--官方文档
    JS问题Uncaught ReferenceError:XXXX is not defined
  • 原文地址:https://www.cnblogs.com/wangxiaodai/p/9780375.html
Copyright © 2011-2022 走看看