• Coins POJ


    给出硬币面额及每种硬币的个数,求从1到m能凑出面额的个数。
    Input
    多组数据,每组数据前两个数字为n,m。n表示硬币种类数,m为最大面额,之后前n个数为每种硬币的面额,后n个数为相应每种硬币的个数。 (n<=100,m<=100000,面额<=100000,每种个数<=1000)
    Output
    RT
    Sample Input
    3 10
    1 2 4 2 1 1
    2 5
    1 4 2 1
    0 0
    
    Sample Output
    8
    4
    
    题解:
      真是,先打了一个二进制分组t了,(本来可以过的吧!)。
      正解是n×m的,首先,我们考虑设dp[i][j]表示凑出j这个数字最大还可以剩下几个i号硬币。这个可以省掉第一维.
      dp[j]=-1表示不可以凑出来,转移就是if(dp[j]>=0) dp[j]=c[i];如果用前面的硬币就可以凑出来,那么i号硬币可以一个不用,if(dp[j]>0) dp[j+v[i]]=max(dp[j+v[i]],dp[j]-1);,然后就是很简单的用一个硬币。
      初始化就是dp[0]=c[i],表示凑出0还剩下c[i]个硬币。
    代码:
    二进制分组TLE
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<stdio.h>
    #include<stdlib.h>
    using namespace std;
    int v[2000],num[2000],w[2000],dp[100010];
    int n,m,cnt=0;
    int main(){
        while(1){
            scanf("%d%d",&n,&m);
            if(!n&&!m) break;
            memset(dp,0,sizeof(dp));
            dp[0]=1;cnt=0;
            for(int i=1;i<=n;i++) scanf("%d",&v[i]);
            for(int i=1;i<=n;i++) scanf("%d",&num[i]);
            for(int i=1;i<=n;i++){
                for(int j=1;num[i]>0;j*=2){
                    int x=min(num[i],j);
                    num[i]-=x;
                    w[++cnt]=x*v[i];
                }
            }
            for(int i=1;i<=cnt;i++){
                for(int j=m;j>=w[i];j--){
                    dp[j]|=dp[j-w[i]];
                }
            }
            int ans=0;
            for(int i=1;i<=m;i++) ans+=dp[i];
            printf("%d
    ",ans);
        }
    }

    AC
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <iostream>
    #define MAXN 100000+1
    #define RG register
    using namespace std;
    int dp[MAXN],v[MAXN],c[MAXN];
    int n,m;
    int main()
    {
        while(1){
            scanf("%d%d",&n,&m);
            if(!n&&!m) break;
            for(int i=1;i<=n;i++) scanf("%d",&v[i]);
            for(int i=1;i<=n;i++) scanf("%d",&c[i]);
            memset(dp,-1,sizeof(dp));
            dp[0]=0;
            for(RG int i=1;i<=n;i++){
                for(RG int j=0;j<=m;j++){
                    if(dp[j]>=0) dp[j]=c[i];
                    else dp[j]=-1;
                }
                for(RG int j=0;j<=m-v[i];j++){
                    if(dp[j]>0) dp[j+v[i]]=max(dp[j+v[i]],dp[j]-1);
                }
            }
            int ans=0;
            for(int i=1;i<=m;i++) if(dp[i]>=0) ans++;
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    linux nohup
    并发编程-多进程模块介绍
    并发编程-多进程
    网络编程-粘包现象
    Typora快捷键Mac
    网络编程
    异常处理
    面向对象-元类介绍
    面向对象-内置方法
    面向对象-反射
  • 原文地址:https://www.cnblogs.com/renjianshige/p/7506931.html
Copyright © 2020-2023  润新知