zoukankan      html  css  js  c++  java
  • 基础背包(一)

    hdu 2602 01背包

    许多年前,在泰迪的家乡,有一个人被称为“骨收藏家”。这个人喜欢收集各种各样的骨头,比如狗的,牛的,他也去了坟墓

    采骨者有一个体积为v的大袋子,在他的采集过程中有很多骨头,很明显,不同的骨头有不同的价值和体积,现在考虑到每一块骨头的价值,你能计算出采骨者能得到的总价值的最大值吗

    输入

    第一行包含整数t,即事例数。

    接下来是t例,每例三行,第一行包含两个整数n,v,(n<=1000,v<=1000),表示骨骼数量和他的包的体积。第二行包含n个整数,表示每个骨骼的值。第三行包含n个整数,表示每个骨骼的体积。

    产量 

    每行一个整数,表示总值的最大值(此数字将小于2 31)。

    解题思路:简单01背包

    一维解法:

    #include<iostream>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int maxn=1100;
    int n,V,dp[maxn],weight[maxn],value[maxn],num[maxn];
    int main(){
        int t;
        cin>>t;
        while(t--){
            cin>>n>>V;
            for(int i=1;i<=n;i++)cin>>value[i];
            for(int i=1;i<=n;i++)cin>>weight[i];
            memset(dp,0,sizeof(dp));
            for(int i=1;i<=n;i++){
                for(int j=V;j>=weight[i];j--)
                    dp[j]=max(dp[j],dp[j-weight[i]]+value[i]);
            }
            cout<<dp[V]<<endl;
        }
        return 0;
    }

    二维解法:

    #include<iostream>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int maxn=1100;
    int n,V,dp[maxn][maxn],weight[maxn],value[maxn],num[maxn];
    
    int main(){
        int t;
        cin>>t;
        while(t--){
            cin>>n>>V;
            for(int i=1;i<=n;i++)cin>>value[i];
            for(int i=1;i<=n;i++)cin>>weight[i];
            memset(dp,0,sizeof(dp));
            for(int i=1;i<=n;i++){
                for(int j=0;j<=V;j++){
                    if(j>=weight[i])dp[i][j]=max(dp[i-1][j],dp[i-1][j-weight[i]]+value[i]);
                    else dp[i][j]=dp[i-1][j];
                }
            }
            cout<<dp[n][V]<<endl;
        }
        return 0;
    }

    hdu 1114  完全背包

    题目大意:

    输入空的存钱罐的重量以及满了的重量
    输入硬币种类数t
    以下t行输入t种硬币每个硬币的重量以及面值
    求此情况下该存钱罐至少能存的钱数,无解就输出无解
     
    解题思路:完全背包问题,注意初始化,初始化为无穷大表示不合法,如果计算最后还是无穷大则表示无解,把max改成min就好了
    一维解法:
    #include<iostream>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int maxn=11000;
    int n,V,dp[maxn],weight[maxn],value[maxn],num[maxn];
    
    int main(){
        int t;
        cin>>t;
        while(t--){
            int v1,v2;
            cin>>v1>>v2;
            V=v2-v1;
            cin>>n;
            for(int i=1;i<=n;i++)cin>>value[i]>>weight[i];
            memset(dp,0x3f,sizeof(dp));
            dp[0]=0;
            for(int i=1;i<=n;i++)
                for(int j=weight[i];j<=V;j++)
                    dp[j]=min(dp[j],dp[j-weight[i]]+value[i]);
            if(dp[V]==0x3f3f3f3f)puts("This is impossible.");
            else printf("The minimum amount of money in the piggy-bank is %d.
    ",dp[V]);
        }
        return 0;
    }

    二维解法:

    #include<iostream>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int maxn=11000;
    int n,V,dp[505][maxn],weight[maxn],value[maxn],num[maxn];
    
    int main(){
        int t;
        cin>>t;
        while(t--){
            int v1,v2;
            cin>>v1>>v2;
            V=v2-v1;
            cin>>n;
            for(int i=1;i<=n;i++)cin>>value[i]>>weight[i];
            memset(dp,0x3f,sizeof(dp));
            for(int i=0;i<=n;i++)dp[i][0]=0;
            for(int i=1;i<=n;i++){
                for(int j=1;j<=V;j++){
                    if(j>=weight[i]) dp[i][j]=min(dp[i-1][j],dp[i][j-weight[i]]+value[i]);
                    else dp[i][j]=dp[i-1][j];
                }
            }
            if(dp[n][V]==0x3f3f3f3f)puts("This is impossible.");
            else printf("The minimum amount of money in the piggy-bank is %d.
    ",dp[n][V]);
        }
        return 0;
    }

    hdu 1171 多重背包

    题目大意:给你n个物品的价值和物品的数量,如何分使得A,B所得价值最接近并且A的价值不能小于B

    解题思路:完全背包,背包的容量为价值的总和的一半

    #include<iostream>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    const int maxn=110000;
    int n,V,dp[55][maxn],weight[maxn],value[maxn],num[maxn];
    int main(){
        while(cin>>n){
            if(n<0)break;
            int sum=0;
            memset(dp,0,sizeof(dp));
            for(int i=1;i<=n;i++){
                cin>>value[i]>>num[i];
                weight[i]=value[i];
                sum+=value[i]*num[i];
            }
            V=sum/2;
            if(sum%2)V++;
            for(int i=1;i<=n;i++)
                for(int j=0;j<=num[i];j++)
                    for(int k=V;k>=j*weight[i];k--)
                        dp[i][k]=max(dp[i-1][k],dp[i-1][k-j*weight[i]]+j*value[i]);
            cout<<max(dp[n][V],sum-dp[n][V])<<" "<<min(dp[n][V],sum-dp[n][V])<<endl;
        }
        return 0;
    }

    hdu 2844 多重背包+二进制优化

    题目大意:给出n种硬币的价值以及数目,求这n种硬币可以在1-m中可以支付的价格有多少种

    解题思路:硬币的价值同时也是硬币的代价,dp[j]表示容量为j的背包所可以得到的最大价值,如果等于j表示可以支付价钱j

    #include<iostream>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    const int maxn=110000;
    int n,m,V,dp[maxn],value[maxn],num[maxn],vis[maxn],weight[maxn];
    int main(){
        while(cin>>n>>m){
            if(n==0&&m==0)break;
            for(int i=1;i<=n;i++) cin>>value[i];
            for(int i=1;i<=n;i++) cin>>num[i];
            int ans=0;
            memset(dp,0,sizeof(dp));
            for(int i=1;i<=n;i++){
                if(value[i]*num[i]>m){
                    for(int j=value[i];j<=m;j++)  //完全背包 
                        dp[j]=max(dp[j],dp[j-value[i]]+value[i]);
                }else{
                    //二进制优化01背包 
                    for(int j=1;j<=num[i];j*=2){
                        for(int k=m;k>=j*value[i];k--)
                            dp[k]=max(dp[k],dp[k-j*value[i]]+j*value[i]);
                        num[i]-=j;
                    }
                    if(num[i]){
                        for(int k=m;k>=num[i]*value[i];k--)
                            dp[k]=max(dp[k],dp[k-num[i]*value[i]]+num[i]*value[i]);
                    }
                }
            }
            for(int i=1;i<=m;i++)
            if(dp[i]==i)ans++;
            cout<<ans<<endl;        
        }
        return 0;
    }

    hdu 1059 多重背包+二进制优化

    题目大意:给你6种不同价值的硬币的数量,价值分别是1~6,问你能否可以将这些硬币分成两堆,每堆的价值一样。

    解题思路:和hdu1171很像,把价值总和的一半看成背包容量,计算形成最大的价值是否可以达到价值总和的一半

    #include<iostream>
    #include<cstring>
    #include<cmath>
    using namespace std;
    typedef long long ll;
    const int maxn=110000;
    int n,V,dp[maxn],value[maxn],num[maxn],vis[maxn],weight[maxn];
    int main(){
        int T=0;
        while(cin>>num[1]>>num[2]>>num[3]>>num[4]>>num[5]>>num[6]){
            int sum=0;
            n=6;
            T++;
            for(int i=1;i<=6;i++)sum+=num[i];
            if(sum==0)break;
            sum=0;
            for(int i=1;i<=6;i++){
                value[i]=i;
                sum+=value[i]*num[i];
            }
            printf("Collection #%d:
    ",T);
            if(sum%2){
                puts("Can't be divided.");
                puts("");
                continue;
            }
            V=sum/2;
            memset(dp,0,sizeof(dp));
            for(int i=1;i<=n;i++){
                if(value[i]*num[i]>V){
                    for(int j=value[i];j<=V;j++)  //完全背包 
                        dp[j]=max(dp[j],dp[j-value[i]]+value[i]);
                }else{
                    //二进制优化 
                    for(int j=1;j<=num[i];j*=2){
                        for(int k=V;k>=j*value[i];k--)
                            dp[k]=max(dp[k],dp[k-j*value[i]]+j*value[i]);
                        num[i]-=j;
                    }
                    if(num[i]){
                        for(int k=V;k>=num[i]*value[i];k--)
                            dp[k]=max(dp[k],dp[k-num[i]*value[i]]+num[i]*value[i]);
                    }
                }
            }
            if(dp[V]==V) puts("Can be divided.");
            else puts("Can't be divided.");
            puts("");
        }
        return 0;
    }
  • 相关阅读:
    使用 @Autowired 的时候,到底是写接口还是实现类?
    socket的简单例子
    java 将文件夹所有的文件合并到指定的文件夹下
    java 复制某一文件夹下的所有文件到另一个文件夹下
    java Date日期总结的一些转换的方法
    java 可排序的数值得字符串,转化成list集合后进行的排序的几种方法
    java 查看文件的大小的方法
    java 从一个总的list集合中,去掉指定的集合元素,得到新的集合
    java 可拆成数组的字符串,去掉重复元素的一种方法
    将博客搬至CSDN
  • 原文地址:https://www.cnblogs.com/zjl192628928/p/10651433.html
Copyright © 2011-2022 走看看