• 母函数法解决选课问题和dp多重背包解法


    
    
    Java版的
    import java.util.*;
    
    class solution
    {
      private int T=0;
      private Scanner iner=new Scanner(System.in);
      private int v[]=new int[41];
      private int c[]=new int[41];
      private int s[]=new int[100];
      private int a[]=new int[100];
      private int n,k;
    
      public int select()
      {
        T=iner.nextInt();
        while(T!=0)
        {
          T--;
          n=iner.nextInt();
          k=iner.nextInt();
          for(int i=0;i<k;++i)
          {
             v[i]=iner.nextInt();
             c[i]=iner.nextInt();
          }
          for(int i=0;i<=n&&i<=v[0]*c[0];i+=v[0])
          {
            a[i]=1;
          }
          for(int i=1;i<k;++i)
          {
            for(int j=0;j<=n;j++)
            {
              for(int x=0;(j+x)<=n&&x<=v[i]*c[i];x+=v[i])
              {
                  s[j+x]+=a[j];
              }
            }
            for(int y=0;y<=n;++y)
            {
              a[y]=s[y];
              s[y]=0;
            }
          }
          System.out.println(a[n]); 
          Arrays.fill(a, 0);
          Arrays.fill(s,0);
        }
        return 0;
      }
    }
    
    public class Main {
        public static void main(String[] args) {
            solution space = new solution();
            space.select();
        }
    }
    
    
    
    import java.util.*;
    
    /**
        * 为什么解决不了选课组合问题
        * 但是可以解决最大价值的问题
        * 还有种多重背包问题是在一堆数中能否找到能组合成n容量的物品
        * 而选课问题就是将所有能组合的种数算出来
        * 两者之间有什么区别
        * 母函数用多重背包解决的状态转移方程:dp[0]=1;和dp[j]=(dp[j]+dp[j-k*p[i]])
        * 多重背包解决思路:我们可以将完全背包转化为01背包求解,我们可以把 一个物品拆分成k个物品(w[x]*k<=C),然后按照01背包求解即可.
        * 那么如果价值相同的物品没有区别呢?
        * for (i = 1; i <= m; i++)
        *        for (j = n; j >= a[i]; j--)
        *            for (k = 1; k <= num[i] && (j - k * a[i]) >= 0; k++)   //k用来表示的是数量,将这个物品看成整体去算对于背包容量来说的各种情况一层一层的去推
        *                dp[j] = dp[j] + dp[j - k * a[i]];        
        * 这段代码可以避免相同的物品却表现出不一样;一层一层的去算
        */
    
    class Solution
    {
       private int v[];   //价值
       private int c[];   //数量
       //private int w[];   //体积
       private int num;   //物品的种数
       private int k;     //物品的总数
       private int dp[];  //最大价值表
       private int cnt;   //背包的最大容量 
       private Scanner iner=new Scanner(System.in);
    
       public int Selected()
       {
           dp[0]=1;
        for(int i=0;i<this.k;++i)
        {
            for(int j=this.cnt;j>=this.v[i];--j)
            {
                for(int k=1;k<=this.c[i]&&(j-k*this.v[i])>=0;++k)
                {
                    dp[j]=dp[j]+dp[j-k*this.v[i]];
                    //dp[j]=Math.max(dp[j], dp[j-this.v[i]]+1);  
                }
                  
            }
        }
        return dp[this.cnt];
       }
    
       public Solution()
       { 
           System.out.print("请输入要修的学分:");
           this.cnt=iner.nextInt();
           System.out.print("请输入课程的种数:");
            this.num=iner.nextInt();
            this.c=new int[this.num+100];
            //this.w=new int[this.num+100];
            this.dp=new int[this.num+100];
            this.v=new int[this.num+100];
           System.out.print("请输入每种课的学分及数量:");
           for(int i=0;i<this.num;++i)
           {
            this.v[i]=iner.nextInt();
            //this.w[i]=iner.nextInt();
            this.c[i]=iner.nextInt();
           }
           this.k=this.num;
           /* for(int i=0;i<this.num;++i)
           {
            while(this.c[i]!=1)
            {
              this.v[k]=this.v[i];
              //this.w[k]=this.w[i];
              this.c[i]--;
              this.c[k]=this.c[i];
              k++;
            }
           } */
       }
    }
    #include<stdio.h>
    #include<string.h>
    #include <windows.h>
    
    int c[45],s[45];
    int a[8],b[8];
    int main()
    {
        int T,i,j,t,n,k;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d %d",&n,&k);
            memset(a,0,sizeof(a));
            memset(s,0,sizeof(s));
            for(i=0;i<k;i++)
            scanf("%d%d",&a[i],&b[i]);
            for(i=0;i<=n&&i<=a[0]*b[0];i+=a[0])
            s[i]=1;      //将第一组数据的系数全部初始化为1
            for(i=1;i<k;i++)                                //i从1开始因为第一次性解决了两项,第二次直接从第三项开始
            {
                for(j=0;j<=n;j++)    //j+=a[i-1]为了减少一些不必要的计算||j<=a[i-1]*b[i-1]
                {
                    for(t=0;t+j<=n&&t<=a[i]*b[i];t+=a[i])
                    c[j+t]+=s[j];                            //j代表前一项的指数,t代表后一项的指数 c[j+t]+=s[j]表示两者相乘时的系数相加
                }
                for(j=0;j<=n;j++)
                {
                    s[j]=c[j];  
                    c[j]=0;
                }
            }
            printf("%d
    ",s[n]);
        }
        system("pause");
        return 0;
    } 
  • 相关阅读:
    Eclipse中移除native层编译支持
    从Nginx源代码谈大写和小写字符转化的最高效代码以及ASCII码表的科学
    设计模式入门之原型模式Prototype
    Java 实现原型(Prototype)模式
    Eclipse
    图片3d轮放查看效果(V2.0):使用鼠标拖动实现图片的轮放
    Objective-C之成魔之路【0-序章】
    VC中常见API函数使用方法(经验版)
    zedboard中OLED源码
    Linux(C/C++)下的文件操作open、fopen与freopen
  • 原文地址:https://www.cnblogs.com/z2529827226/p/11628846.html
Copyright © 2020-2023  润新知