zoukankan      html  css  js  c++  java
  • Cookies

    CH

    题意:圣诞老人共有(M)个饼干,准备全部分给(N)个孩子.每个孩子有一个贪婪度,第(i)个孩子的贪婪度为(g[i]).如果有(a[i])个孩子拿到的饼干数比第(i)个孩子多,那么第 (i)个孩子会产生(g[i]*a[i])的怨气.给定(N、M)和序列(g),圣诞老人请你帮他安排一种分配方式,使得每个孩子至少分到一块饼干,并且所有孩子的怨气总和最小,求最小怨气和以及任意一种方案.(1≤N≤30,N≤M≤5000,1<=g[i]<=10^7)

    分析:设(f[i][j])表示前i个人,分了j块饼干,所产生的最小的贪婪值.

    先把所有人按照贪婪度从大到小排序,保证分的饼干数单调递减(这个贪心策略不要证明也能理解吧).

    既然保证了单调性,那就好写转移方程.分两种情况讨论.

    如果第i个人分的饼干数大于1,那么等价于前i个人分了j-i个饼干,即每个人少拿一块饼干(这样做相对大小不变,所以贪婪值也不会变,不影响结果):

    (f[i][j]=f[i][j-i])

    如果第i个人获得的饼干数为1,则枚举i前面有多少个人也获得1块饼干:

    (f[i][j]=min_{0<=k<i} f[k,j-(i-k)]+k*sum_{p=k+1}^i g[p])

    初始化(f[0][0]=0),其余赋值为正无穷.目标(f[n][m])

    题目还要求方案,再开一个(pre[i][j])表示前i个人,分了j块饼干时的转移路径.

    如果(f[i][j]=f[i][j-i]),则(pre[i][j]=i)

    如果是另一种情况,则(pre[i][j]=k)

    如何输出方案时,同理也要分情况讨论,详见代码.

    #include<bits/stdc++.h>
    using namespace std;
    inline int read(){
        int s=0,w=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
        return s*w;
    }
    const int N=35;
    int sum[N],ans[N],f[N][5005],pre[N][5005];
    struct ppx{
        int g,num;
    }a[N];
    inline bool cmp(const ppx &x,const ppx &y){return x.g>y.g;}
    int main(){
        int n=read(),m=read();
        for(int i=1;i<=n;i++)a[i].g=read(),a[i].num=i;
        sort(a+1,a+n+1,cmp);
        for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i].g;
        memset(f,0x3f,sizeof(f));f[0][0]=0;
        for(int i=1;i<=n;i++)
    		for(int j=i;j<=m;j++){
    	    	f[i][j]=f[i][j-i];pre[i][j]=i;
    	    	for(int k=0;k<i;k++)
    				if(f[i][j]>f[k][j-(i-k)]+k*(sum[i]-sum[k])){
    		    		f[i][j]=f[k][j-(i-k)]+k*(sum[i]-sum[k]);
    		    		pre[i][j]=k;
    				}
    		}
        printf("%d
    ",f[n][m]);
    //输出方案:(DP如何分类如何转移,输出方案时也同样做)
        int nn=n,mm=m;
        while(nn){
    //如果是第一种情况,根据上述分析,把每个人的饼干数减1是等价的,所以每个人都可以分到一块饼干
    		if(pre[nn][mm]==nn){
    	    	for(int i=1;i<=nn;i++)ans[a[i].num]++;
    	    	mm-=nn;
    		}
    //情况2,只有k+1到n分的饼干数一样,就一起处理,每个人都可以分到一块饼干.
    		else{
    	    	for(int i=pre[nn][mm]+1;i<=nn;i++)ans[a[i].num]++;
    	    	int k=pre[nn][mm];mm=mm-(nn-k);nn=k;
    		}
        }
        for(int i=1;i<=n;i++)printf("%d ",ans[i]);puts("");
        return 0;
    }
    
    
  • 相关阅读:
    祥解使用 SQL Server 2005/2008 发送数据库邮件
    将Virtual Server 2005 的虚拟硬盘(VHD)文件复制到HyperV
    Win2008 64位 iis7 环境下安装Discuz!NT
    seo
    找了好办天才找到的asp生成图片学习一下
    1.1 开发背景 (学习图书连载csdn
    我眼中的C# 3.0
    google编程
    反射之反思
    我要减肥
  • 原文地址:https://www.cnblogs.com/PPXppx/p/10990714.html
Copyright © 2011-2022 走看看