zoukankan      html  css  js  c++  java
  • hdu 4381(背包变形)

    题意:

    给定n个块,编号从1到n,以及m个操作,初始时n个块是白色。

    操作有2种形式:

    1 ai xi : 从[1,ai]选xi个块,将这些块涂白。

    2 ai xi:从[ai,n]选xi个块,将这些块涂白。

    可以忽略某些操作且如果区间内没有足够的黑块(黑块用于涂白),则不能进行这个操作。

    分析:

    写写画画一看就知道这道题是一个背包问题。

    “恰好装满背包”。

    以下摘自题解:

    本题难点在于正确处理两种操作,不妨假设只有一种操作,那么这种操作如果是1的话那么就把操作按照a从小到大排序,每次都尽量往最左边涂,如果是2的话则类似的涂到最右边,但本题两种操作都出现了。

    先考虑第一问:

    我们把所有的操作按类别区分开,假设所有的1操作尽量用上能从1涂到a格子,所有的2操作尽量用上能从b格子涂到n,假设a<b,那么答案显然是a+n-b+1。那么假设a>=b,那么假设1操作从1涂到x,那么2操作一定会从n尽量往左边涂,直到x为止。最后两边的总和就是答案。

    由上不难想到一个DP,l[i][j]表示用了前i种1操作,从1涂到j的最小操作数,转移l[i][j]=min(l[i][j],l[i-1][j-ope[i].x]+1)(ope[i].x<=j<=ope[i].a),类似的,我们可以得到r[i][j]表示用2操作从j涂到n需要的最小操作数。dp复杂度O(n*m)。(这个背包也可以压缩一维,后面的l,r均为1维的状态)

    那么我们倒着枚举涂色最大的数目,假设为k,这个数目必然由1操作贡献一部分,由2操作贡献一部分(也可能一个贡献全部,另一个为0),那么我们枚举1操作涂到了i,那么2操作必然涂到了n-(k-i)+1,如果l[i]和r[n-(k-i)+1]均有值,那么说明这个最大数目是可达的,即是第一问的答案。枚举复杂度O(n*n)。

    再考虑第二问:

    现在我们已经知道最大数目了,这个数目是由操作1和操作2一起贡献的,那么我们仍然可以枚举操作1涂到了i,那么操作2涂到了n-(ans-i)+1,如果l[i]和r[n-(k-i)+1]均有值,那么其和可以用来更新第二问的答案,最后第二问的答案为所有合法方案需操作数的最小值。枚举复杂度O(n*n)。

    代码实现:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #include <vector>
    #include <cmath>
    
    using namespace std;
    const int maxn = 2005;
    struct node{
        int aa,cor;
        node(){}
        node(int _aa,int _cor){
           aa = _aa;   cor = _cor;
        }
    }x1[maxn],x2[maxn];
    int n,m;
    int dp1[maxn],dp2[maxn];
    int sumx1,sumx2;
    
    bool cmp(const node &p,const node &q){
        return p.aa < q.aa;
    }
    
    int min(int a,int b)
    {
        return a<b?a:b;
    }
    
    int main()
    {
        int cas,ta=1;
        scanf("%d",&cas);
        while(cas--){
             int i,j;
             scanf("%d%d",&n,&m);
    
             sumx1 = sumx2 = 1;
             for(i=0; i<m; i++){
                 int key,yy,z;
                 scanf("%d%d%d",&key,&yy,&z);
                 if(key == 1){
                    x1[sumx1++] = node(yy,z);
                 }else{
                    x2[sumx2++] = node(n+1-yy,z);
                 }
             }
             sort(x1+1,x1+sumx1,cmp);
             sort(x2+1,x2+sumx2,cmp);
             memset(dp1,0x3f,sizeof(dp1));
             memset(dp2,0x3f,sizeof(dp2));
    
             dp1[0] = dp2[0] = 0;
             for(i=1; i<sumx1; i++){
                 for(j=x1[i].aa; j>=x1[i].cor; j--){
                    dp1[j] = min(dp1[j],dp1[j-x1[i].cor]+1);
                 }
             }
    
             for(i=1; i<sumx2; i++){
                 for(j=x2[i].aa; j>=x2[i].cor; j--){
                    dp2[j] = min(dp2[j],dp2[j-x2[i].cor]+1);
                 }
             }
    
             int ans = 0,anssum = 0,tmp;
             for(i=1; i<=n; i++){
                for(j=0; j<=i; j++){
                   tmp = dp1[j] + dp2[i-j];
                   if(tmp <= m){
                      if(ans != i){
                        ans = i;   anssum = tmp;
                      }else if(tmp < anssum){
                          anssum = tmp;
                      }
                   }
                }
             }
    
             printf("Case %d: %d %d
    ",ta++,ans,anssum);
        }
        return 0;
    }
  • 相关阅读:
    Android5.0 Gallery2上编译Gallery模块出错
    Ubuntu Linux系统下的SVN客户端工具PySVN
    ubuntu下如何安装及使用 pysvn-workbench
    系统数据库开启
    Ubuntu下使用SVN
    Ubuntu Linux 环境变量
    android 权限管理和签名 实现静默卸载
    Android系统权限及签名
    Android Security
    《Java程序猿面试笔试宝典》之字符串创建与存储的机制是什么
  • 原文地址:https://www.cnblogs.com/jiangjing/p/3855015.html
Copyright © 2011-2022 走看看