• 4月21日


    poj1742

    题意:有n种物体,每种有ci个,权值为ai,问能组成1到m之间的多少个数

    分析:楼教主著名的“男人八题”中的一题,很经典的dp问题,参照《挑战程序设计》上的多重部分和问题,定义bool型的dp[i+1][j],表示前i个数能否得到j,于是就有前i-1个数得到j-k*a[i](0<=k<=c[i]),但是o(n^3),超时了

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <string>
     5 #include <vector>
     6 #include <algorithm>
     7 #include <set>
     8 #include <map>
     9 #include <bitset>
    10 #include <cmath>
    11 #include <queue>
    12 #include <stack>
    13 using namespace std;
    14 const int maxn=120;
    15 const int maxm=100002;
    16 int a[maxn],c[maxn];
    17 bool dp[maxn][maxm];
    18 int n,m;
    19 int main()
    20 {
    21     while(cin>>n>>m)
    22     {
    23         if(n+m==0) break;
    24         for(int i=0;i<n;i++)
    25             cin>>a[i];
    26         for(int i=0;i<n;i++)
    27             cin>>c[i];
    28         memset(dp,false,sizeof(dp));
    29         dp[0][0]=true;
    30         for(int i=0;i<n;i++)
    31         {
    32             for(int j=0;j<=m;j++)
    33             {
    34                 for(int k=0;k<=c[i]&&k*a[i]<=j;k++)
    35                     dp[i+1][j]|=dp[i][j-k*a[i]];
    36             }
    37         }
    38         int cnt=0;
    39         for(int i=1;i<=m;i++)
    40             if(dp[n][i])
    41                 cnt++;
    42         cout<<cnt<<endl;
    43     }
    44     return 0;
    45 }
    TLE

    紧接着,参照书上的另外一种解法得到了新的做法,令dp[i+1][j]表示前i个数得到j时第i个数还剩余多少个,于是有了三种情况,(1)若前i-1个已经得到j了,则第i种有c[i]个,(2)若j<a[i]或者dp[i+1][j-a[i]]<=0,则前i个数无法得到j,(3)否则为前i个数得到j-a[i]的个数减1,所以得到如下方程:

    • dp[i][j]>=0,dp[i+1][j]=c[i]
    • j<a[i]||dp[i+1][j-a[i]]<=0,dp[i+1][j]=-1
    • dp[i+1][j]=dp[i+1][j-a[i]]-1

    注意这里要用滚动数组,不然内存会爆,总的来说还是一个非常值得学习的题目,orz楼教主

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <string>
     5 #include <vector>
     6 #include <algorithm>
     7 #include <set>
     8 #include <map>
     9 #include <bitset>
    10 #include <cmath>
    11 #include <queue>
    12 #include <stack>
    13 using namespace std;
    14 const int maxn=120;
    15 const int maxm=100002;
    16 int a[maxn],c[maxn];
    17 int dp[maxm];
    18 int n,m;
    19 int main()
    20 {
    21     while(cin>>n>>m)
    22     {
    23         if(n+m==0)  break;
    24         for(int i=0;i<n;i++)
    25             scanf("%d",&a[i]);
    26         for(int i=0;i<n;i++)
    27             scanf("%d",&c[i]);
    28         memset(dp,-1,sizeof(dp));
    29         dp[0]=0;
    30         for(int i=0;i<n;i++)
    31         {
    32             for(int j=0;j<=m;j++)
    33             {
    34                 if(dp[j]>=0)
    35                     dp[j]=c[i];
    36                 else if(j<a[i]||dp[j-a[i]]<=0)
    37                     dp[j]=-1;
    38                 else
    39                     dp[j]=dp[j-a[i]]-1;
    40             }
    41         }
    42         int cnt=0;
    43         for(int i=1;i<=m;i++)
    44             if(dp[i]>=0)
    45                 cnt++;
    46         printf("%d
    ",cnt);
    47     }
    48     return 0;
    49 }
    Accept
  • 相关阅读:
    js38---门面模式
    js37---Function.prototype
    js36---函数嵌套
    js35
    js34
    js33--责任链模式
    js32---CommonUtil.js
    龙芯服务器参数
    SQLSERVER 秘钥整理
    IOMETER的简单使用
  • 原文地址:https://www.cnblogs.com/wolf940509/p/5418913.html
Copyright © 2020-2023  润新知