zoukankan      html  css  js  c++  java
  • dp之分组背包hdu3033 最少取1次的解法(推荐)

    题意:有n双鞋子,m块钱,k个品牌,(一个品牌可以有多种价值不同的鞋子),接下来n种不同的鞋子,a为所属品牌,b为要花费的钱,c为所能得到的价值。每种价值的鞋子只会买一双,有个人有个伟大的梦想,每个品牌的鞋子至少买一双,问他这个梦想可以实现不?不可以实现输出Impossible,可以实现输出最大价值......

    思路:很容易看出来这是个分组背包题,当然这个分组背包有些不同于每组最多取一个的分组背包......但我是觉得,分组背包就这么几种问法吧

    1、最常见的、最水的,每组最多取1个.........(一般是隐性的,需要自己分析)

    2、每组至少取1个........(就是本题)

    3、随意选,可以选,可以不选,可以只选1个,也可以选多个......(暂时还未学,马上会学).....

    对于第一种,模板题,只要你可以分析出来,那么可以水过.....

    对于第二种,我想说也是模板题,当然是以本题为基础的模板.........

    好吧,这道题目,首先,每组至少取一个,就是说必须要取一个,那么数组dp[i][j],代表的含义就是 前i组容量为j的情况下所得到的最大价值为dpi][j];

    同样的,我们首先思考它的状态,每组必须要取一个,那么第i组存在的情况下,第i-1组也必须存在,也是回到了前面所做背包所说的那种“一定”、“必须”的状态,那么同样的在动态转移的时候,要判断它的前一个状态合不合法,我个人比较喜欢用0来判断不合法,>0判断合法.......初始化dp[0][0]=1,最后得到的结果减去1......我想说的是,最后的结果不一定会集中在dp[k][m]上,因为这个状态它不一定存在,也就是说,这个状态不一定合法,当然,也没有关系,我们考虑第k组一定要存在,那么扫描下dp[k][i],取最大值就好.....

    #include<iostream>
    #include<stdio.h>
    #include<string.h>
    #include<queue>
    using namespace std;
    int dp[15][10005],s[105][2],num[15][105];
    queue<int>Q[105];
    int main()
    {
        int n,m,k;
        while(scanf("%d %d %d",&n,&m,&k)>0)
        {
              
              for(int i=0;i<105;i++)
              while(!Q[i].empty())
              Q[i].pop();
              for(int i=1;i<=n;i++)
              {
                   int a,b,c;
                   scanf("%d %d %d",&a,&b,&c);
                   Q[a].push(i);
                   s[i][0]=b;
                   s[i][1]=c;
              }
              
              for(int i=1;i<=k;i++)
              {
                   int j=1;
                   while(!Q[i].empty())
                   {
                        num[i][j++]=Q[i].front();
                        //printf("i==%d %d
    ",i,Q[i].front()); 
                        Q[i].pop();
                   }
                   num[i][0]=j;
              }                                 //前面都是将数据处理好 
              memset(dp,0,sizeof(dp));       //初始化dp 
              dp[0][0]=1;
              int flag=1;
              for(int i=1;i<=k;i++)        //这是分组 
              {
                  if(num[i][0]==1)        //要是有一组没有数据,那么说明,它不可能满足每组必须取一个这条件....... 
                  {
                        flag=0;
                        break;
                  }
                  for(int f=1;f<num[i][0];f++)     //不同于最多取一个的分组背包,这里是先放每组有的物品,后放容积....... 
                  {
                       int xx=num[i][f];;
                       for(int j=m;j>=0;j--)        //至于为什么这么放?我是认为,它是一种模板....... 
                       {
                            if(j-s[xx][0]>=0&&dp[i][j-s[xx][0]]&&dp[i][j-s[xx][0]]+s[xx][1]>dp[i][j]) //这个判断必须放到第一,以免重复 
                            dp[i][j]=dp[i][j-s[xx][0]]+s[xx][1];
                            
                            if(j-s[xx][0]>=0&&dp[i-1][j-s[xx][0]]&&dp[i-1][j-s[xx][0]]+s[xx][1]>dp[i][j])//这个必须放在上一个判断下面..... 
                            dp[i][j]=dp[i-1][j-s[xx][0]]+s[xx][1];
                            
                       }
                  }
              }
              int maxx=0;
              for(int i=0;i<=m;i++)
              if(maxx<dp[k][i])
              maxx=dp[k][i];
              if(maxx==0||flag==0)
              printf("Impossible
    ");
              else
              printf("%d
    ",maxx-1);//最大值记得减去1 
        }
        return 0;
    }
    
  • 相关阅读:
    密文搜索
    poj 1182 食物链
    1147. Heaps (30)
    1146. Topological Order (25)
    1145. Hashing
    1142. Maximal Clique (25)
    fzu 2112 tickets
    51nod 1554 欧姆诺姆和项链
    codeforces 963B Destruction of a Tree
    hdu 3294 Girls' research
  • 原文地址:https://www.cnblogs.com/ziyi--caolu/p/3223306.html
Copyright © 2011-2022 走看看