dp(路径字典序输出)

今天做了一道01背包加最小字典序输出的问题,就稍微总结一下然后说些理解,如果有错还望大神指出。
题目地址戳这里
路径的存储有两种方法,一种是用path二维数组记录一下路径,另一种是直接根据dp数组逆着找回去.
第一种方法:优化后和没优化的dp数组都可以使用
第二种方法:只能用于没有优化后的dp数组,一维存的信息不够.(因为一维边存边丢.)
至于要输出字典序最小的方案,采取贪心的思想,从第一个物品开始判断取还是不取,那么此时在dp的时候我们也要从后往前看每个物品。而要输出字典序最大的方案那么就直接从后面向前面看就可以了

for(int i=1;i<=n;i++)  //n个物品,用结构体Input存储
    {
        for(int j=m;j>=input[i].cost;j--)
        {
            dp[j]=dp[j];
            if(dp[j-input[i].cost]+input[i].v>dp[j])
            {
                path[i][j]=1;  //path 记录路径
                dp[j]=dp[j-input[i].cost]+input[i].v;
            }
        }
    }
    int i=n,j=m;
    while(i&&j)
    {
        if(path[i][j]==1)
        {
            printf("%d\n",i);  //拿了第i个物品,输出方案
            j-=input[i].cost;
        }
        i--;
    }

方法二

for(int i=1;i<=n;i++)  //n个物品,用结构体Input存储
    {
        for(int j=input[i].cost;j<=m;j++)   //m是背包容量
        {
            dp[i][j]=max(dp[i-1][j],dp[i-1][j-input[i].cost]+input[i].v);
        }
    }
    int i=n,j=m;
    while(i&&j)
    {
        if(dp[i][j]==dp[i-1][j-input[i].cost]+input[i])
        {
            printf("%d\n",i);
            j-=input[i].cost;
        }
        i--;
    }
//如果要输出最小字典序
for(int i=n;i>=1;i--)   //从最后一个物品开始拿,此时dp[i][j]表示后n-i+1个物品中体积为j时的最大价值
{
    for(int j=V;j>=0;j--)
    {
        if(j>=v[i])
            dp[i][j]=max(dp[i+1][j],dp[i+1][j-v[i]]+w[i]);  //v[i]第i 个物品的体积,w[i]第i个物品的价值
        else
            dp[i][j]=dp[i+1][j];
    }
}
//输出路径的方案
int i=1,j=V;
while(i<=n&&j>0)   //从第一个物品开始看拿没拿
 {
     if(j>=v[i]&&dp[i][j]==dp[i+1][j-v[i]]+w[i]) {
         j-=v[i];
         cout<<i<<' ';
     } //拿了就输出,再把体积减去,值得注意一下的是边界条件j>=v[i],如果没有这个条件的话就会出现数组下标越界答案出错。
     i++;  //判断下一个物品
 }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值