hdu 2126 DP 方案数背包

原文转自:haha593572013

原文地址链接:http://blog.csdn.net/crazy_ac/article/details/7869411

http://acm.hdu.edu.cn/showproblem.php?pid=2126

题意:给你n种物品以及每种物品的价格,m的钱,问你在满足买最多种物品的前提下,有多少种不同的够买方案

解法1:

首先献上我的比较挫的方法,也是大众化的方法,dp[i][j][k]表示前i种物品,买了j个,花了小于等于k的钱的时候的方案数

因为是小于等于k,所以初始化的时候要注意哦。



转移的时候的情况dp[i][j][k]的情况会有两种,一种是放入了第i件,一种是没有放入第i件,最后都达到了J件,这两种可能合起来就是总方案数.

ps:由动态方程到实现的过程中,一般意识是,类似于数学归纳法,知道第一层的状态不断地递推下去,所以,只需要确保第一层状态已经建立,然后开始递推,在递推的过程中需要注意有没有冒着重复计算的风险。

  1. dp[i][j][k]+=dp[i-1][j-1][k-p[i]];  
  2.  dp[i][j][k]+=dp[i-1][j][k];  

  1. #include<cstdio>  
  2. #include<cstring>  
  3. #include<algorithm>  
  4. using namespace std;  
  5. int dp[35][35][510];  
  6. int p[35];  
  7. int main()  
  8. {  
  9.     int t,m,n;  
  10.     scanf("%d",&t);  
  11.     while(t--)  
  12.     {  
  13.         scanf("%d%d",&n,&m);  
  14.         for(int i=1;i<=n;i++) scanf("%d",&p[i]);  
  15.         memset(dp,0,sizeof(dp));  
  16.         for(int i=0;i<=n;i++)  
  17.         {  
  18.             for(int j=0;j<=m;j++)  
  19.                dp[i][0][j]=1;  
  20.         }  
  21.         for(int i=1;i<=n;i++)  
  22.         {  
  23.             for(int j=1;j<=i;j++)  
  24.             {  
  25.                 for(int k=m;k>=0;k--)  
  26.                 {  
  27.                     if(k>=p[i])   dp[i][j][k]+=dp[i-1][j-1][k-p[i]];  
  28.                      dp[i][j][k]+=dp[i-1][j][k];  
  29.                 //  printf("i=%d j=%d k=%d %d\n",i,j,k,dp[i][j][k]);  
  30.                 }  
  31.             }  
  32.         }  
  33.         int ops=-1,kinds=-1;  
  34.         for(int i=n;i>=1;i--)  
  35.         {  
  36.             for(int j=i;j>=1;j--)  
  37.             {  
  38.                 for(int k=m;k>=0;k--)  
  39.                 {  
  40.                     if(dp[i][j][k])  
  41.                     {  
  42.                         //printf("%d %d %d\n",i,j,k);  
  43.                         kinds=j;  
  44.                         ops=dp[i][j][k];  
  45.                         break;  
  46.                     }  
  47.                 }  
  48.                 if(kinds!=-1) break;  
  49.             }  
  50.             if(kinds!=-1) break;  
  51.         }  
  52.         if(ops!=-1)  
  53.         {  
  54.             printf("You have %d selection(s) to buy with %d kind(s) of souvenirs.\n",ops,kinds);  
  55.         }  
  56.         else printf("Sorry, you can't buy anything.\n");  
  57.     }  
  58.     return 0;  
  59. }  


解法二:直接变成rank2了!!!

其实也很简单,可以这样设计状态开一个dp[30][500][2]的数组,dp[i][j][0]就表示前i个物品,花了 <= j 的钱,最多可以买到的纪念品数量,dp[i][j][1]就表示买到最多纪念品前提下的方案数了,转移的时候就按照关键字来转移,

先判断能否增加所买的纪念品的种类数,

再判断种类数相同的时候的情况

  1. #include<cstdio>  
  2. #include<cstring>  
  3. #include<iostream>  
  4. using namespace std;  
  5. int dp[31][501][2];  
  6. int v[31];  
  7. int main()  
  8. {  
  9.     int t,m,n;  
  10.     scanf("%d",&t);  
  11.     while(t--)  
  12.     {  
  13.         scanf("%d%d",&n,&m);  
  14.         for(int i=1;i<=n;i++) scanf("%d",&v[i]);  
  15.         memset(dp,0,sizeof(dp));  
  16.         for(int i=0;i<=m;i++) dp[0][i][1]=1;  
  17.         for(int i=0;i<=n;i++) dp[i][0][1]=1;  
  18.         for(int i=1;i<=n;i++)  
  19.         {  
  20.             for(int j=0;j<v[i];j++) dp[i][j][0]=dp[i-1][j][0],dp[i][j][1]=dp[i-1][j][1];  
  21.             for(int j=v[i];j<=m;j++)  
  22.             {  
  23.                 if(dp[i-1][j-v[i]][0]+1>dp[i-1][j][0])  
  24.                 {  
  25.                     dp[i][j][0]=dp[i-1][j-v[i]][0]+1;  
  26.                     dp[i][j][1]=dp[i-1][j-v[i]][1];  
  27.                 }  
  28.                 else if(dp[i-1][j-v[i]][0]+1==dp[i-1][j][0])  
  29.                 {  
  30.                     dp[i][j][0]=dp[i-1][j][0];  
  31.                     dp[i][j][1]=dp[i-1][j][1]+dp[i-1][j-v[i]][1];  
  32.                 }  
  33.                 else   
  34.                 {  
  35.                     dp[i][j][0]=dp[i-1][j][0];  
  36.                     dp[i][j][1]=dp[i-1][j][1];  
  37.                 }  
  38.             }  
  39.         }  
  40.         if(dp[n][m][0]) printf("You have %d selection(s) to buy with %d kind(s) of souvenirs.\n",dp[n][m][1],dp[n][m][0]);  
  41.         else printf("Sorry, you can't buy anything.\n");  
  42.     }  
  43.     return 0;  
  44. }  


解法三:rank1

优化是永无止境的~    突然发现只有最后一层的状态有用,那就用滚动数组试试吧

结果,直接跑到了rank1

精益求精,截图留念一下


  1. #include<cstdio>  
  2. #include<cstring>  
  3. #include<iostream>  
  4. using namespace std;  
  5. int dp[501][2], v[31];  
  6. int main()  
  7. {  
  8.     int t,m,n;  
  9.     scanf("%d",&t);  
  10.     while(t--)  
  11.     {  
  12.         scanf("%d%d",&n,&m);  
  13.         for(int i=1;i<=n;i++) scanf("%d",&v[i]);  
  14.         memset(dp,0,sizeof(dp));  
  15.         for(int i=0;i<=m;i++) dp[i][1]=1;  
  16.         for(int i=1;i<=n;i++)  
  17.         {  
  18.             dp[0][1]=1;  
  19.             for(int j=m;j>=v[i];j--)  
  20.             {  
  21.                 if(dp[j-v[i]][0]+1>dp[j][0])  
  22.                 {  
  23.                     dp[j][0]=dp[j-v[i]][0]+1;  
  24.                     dp[j][1]=dp[j-v[i]][1];  
  25.                 }  
  26.                 else if(dp[j-v[i]][0]+1==dp[j][0])  
  27.                 {  
  28.                     dp[j][1]=dp[j][1]+dp[j-v[i]][1];  
  29.                 }  
  30.             }  
  31.         }  
  32.         if(dp[m][0]) printf("You have %d selection(s) to buy with %d kind(s) of souvenirs.\n",dp[m][1],dp[m][0]);  
  33.         else printf("Sorry, you can't buy anything.\n");  
  34.     }  
  35.     return 0;  
  36. }  

还有些人竟然可以用0kb的内存,- -!,难道是纯数学方法?



建议不通过注释看懂代码,我看完之后懂了好多东西.

以下为注释代码:

<span style="font-size:18px;"># include<iostream>
# include<cstdio>
# include<cstring>
using namespace std;
/*
dp[i][j][0]=dp[i-1][j][0] || dp[i][j][0]=dp[i-1][j-p[i]][0];
if(j>=p[i]) dp[i][j][1]+=dp[i-1][j-p[i]][1]
    dp[i][j][1]+=dp[i-1][j][1]
*/
int dp[35][510][2],v[35];

int main()
{
    int t,m,n,i,j,k;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d",&n,&m);
        for(i=1;i<=n;i++) scanf("%d",&v[i]);
        memset(dp,0,sizeof(dp));
        //方案数0层初始化

        for(i=0;i<=n;i++) dp[i][0][1]=1;
        for(i=0;i<=m;i++) dp[0][i][1]=1;

        for(i=1;i<=n;i++)
          {
            for(j=0;j<v[i];j++)//二维数组确定了各阶段状态的独立性,无须从j=m开始,第i个不放下的状态转移
                dp[i][j][0]=dp[i-1][j][0],dp[i][j][1]=dp[i-1][j][1];
            for(j=v[i];j<=m;j++)//第i个放下的状态转移
            {
                if(dp[i-1][j-v[i]][0] +1 >dp[i-1][j][0])//可以放下,而且放下之后比之前的个数多
                {
                    dp[i][j][0]=dp[i-1][j-v[i]][0]+1;
                    dp[i][j][1]=dp[i-1][j-v[i]][1];
                }
                else if( dp[i-1][j-v[i]][0]+1==dp[i-1][j][0] )//可以放下,而且放下后的个数与原个数相等
                {
                    dp[i][j][0]=dp[i-1][j][0];
                    dp[i][j][1]=dp[i-1][j][1]+dp[i-1][j-v[i]][1];
                }
                else//可以放下,而且放下后的个数比原个数小
                {
                    dp[i][j][0]=dp[i-1][j][0];
                    dp[i][j][1]=dp[i-1][j][1];
                }
            }
          }

          if(dp[n][m][0])//至少可以购买一个
            printf("You have %d selection(s) to buy with %d kind(s) of souvenirs.\n",dp[n][m][1],dp[n][m][0]);
          else
            printf("Sorry, you can't buy anything.\n");
    }
    return 0;
}







# include<iostream>
# include<cstdio>
# include<cstring>
using namespace std;
int dp[510][2],p[35];
int main()
{
        int t,i,j,n,m;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d %d",&n,&m);
            for(i=1;i<=n;i++)
                scanf("%d",&p[i]);
            memset(dp,0,sizeof(dp));
            for(i=0;i<=m;i++)
                dp[i][1]=1;

            for(i=1;i<=n;i++)//用01背包的解法,重量变成了个数,利用个数的变化与方案数的联系求得方案数
                for(j=m;j>=p[i];j--)//保证状态独立性
                {
                    if( dp[j-p[i]][0]+1>dp[j][0] )//可以放下,而且放下之后个数比原来大
                      {
                            dp[j][0]=dp[j-p[i]][0]+1;
                            dp[j][1]=dp[j-p[i]][1];
                      }
                    else if(dp[j-p[i]][0]+1==dp[j][0] )//放下之后个数和原谅相等
                            dp[j][1]=dp[j-p[i]][1]+dp[j][1];
                }
            if(dp[m][0])
                printf("You have %d selection(s) to buy with %d kind(s) of souvenirs.\n",dp[m][1],dp[m][0]);
            else
            printf("Sorry, you can't buy anything.\n");
        }
    return 0;
}</span>




在使用Python来安装geopandas包时,由于geopandas依赖于几个其他的Python库(如GDAL, Fiona, Pyproj, Shapely等),因此安装过程可能需要一些额外的步骤。以下是一个基本的安装指南,适用于大多用户: 使用pip安装 确保Python和pip已安装: 首先,确保你的计算机上已安装了Python和pip。pip是Python的包管理工具,用于安装和管理Python包。 安装依赖库: 由于geopandas依赖于GDAL, Fiona, Pyproj, Shapely等库,你可能需要先安装这些库。通常,你可以通过pip直接安装这些库,但有时候可能需要从其他源下载预编译的二进制包(wheel文件),特别是GDAL和Fiona,因为它们可能包含一些系统级的依赖。 bash pip install GDAL Fiona Pyproj Shapely 注意:在某些系统上,直接使用pip安装GDAL和Fiona可能会遇到问题,因为它们需要编译一些C/C++代码。如果遇到问题,你可以考虑使用conda(一个Python包、依赖和环境管理器)来安装这些库,或者从Unofficial Windows Binaries for Python Extension Packages这样的网站下载预编译的wheel文件。 安装geopandas: 在安装了所有依赖库之后,你可以使用pip来安装geopandas。 bash pip install geopandas 使用conda安装 如果你正在使用conda作为你的Python包管理器,那么安装geopandas和它的依赖可能会更简单一些。 创建一个新的conda环境(可选,但推荐): bash conda create -n geoenv python=3.x anaconda conda activate geoenv 其中3.x是你希望使用的Python版本。 安装geopandas: 使用conda-forge频道来安装geopandas,因为它提供了许多地理空间相关的包。 bash conda install -c conda-forge geopandas 这条命令会自动安装geopandas及其所有依赖。 注意事项 如果你在安装过程中遇到任何问题,比如编译错误或依赖问题,请检查你的Python版本和pip/conda的版本是否是最新的,或者尝试在不同的环境中安装。 某些库(如GDAL)可能需要额外的系统级依赖,如地理空间库(如PROJ和GEOS)。这些依赖可能需要单独安装,具体取决于你的操作系统。 如果你在Windows上遇到问题,并且pip安装失败,尝试从Unofficial Windows Binaries for Python Extension Packages网站下载相应的wheel文件,并使用pip进行安装。 脚本示例 虽然你的问题主要是关于如何安装geopandas,但如果你想要一个Python脚本来重命名文件夹下的文件,在原始名字前面加上字符串"geopandas",以下是一个简单的示例: python import os # 指定文件夹路径 folder_path = 'path/to/your/folder' # 遍历文件夹中的文件 for filename in os.listdir(folder_path): # 构造原始文件路径 old_file_path = os.path.join(folder_path, filename) # 构造新文件名 new_filename = 'geopandas_' + filename # 构造新文件路径 new_file_path = os.path.join(folder_path, new_filename) # 重命名文件 os.rename(old_file_path, new_file_path) print(f'Renamed "{filename}" to "{new_filename}"') 请确保将'path/to/your/folder'替换为你想要重命名文件的实际文件夹路径。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值