【dp/01背包/路径还原】HRBUST 1740 A Story on a Sunshine Beach

13 篇文章 0 订阅

A Story on a Sunshine Beach

Time Limit: 1000 MS Memory Limit: 65535 K

Description

Baby H bring his MM to a sunshine beach. There are a lot of beautiful stones. MM scores the stones by their outward appearance.
The higher score it gets, the more beautiful the stone is.
Then mm number the stones by its tactile impression. The smaller the number is, the better the tactile impression is.
Baby H’s bag has a maximum load-bearing m, they want to get home with the maximum sum of score and the minimum number of stones. Of course, outward appearance is the most important.

Input

There are multiple test cases. The first line is a positive integer T indicating the number of test cases.

For each test case, the first line is two positive integer n and m, standing for the number of stones and the load-bearing of Baby H’s bag.

Then n lines follow. Each line contains two integers standing for the weight and score of each stone.

(1<=n<=100, 1<=m<=1000, 1<=ai<=100, 1<=bi<=100).

Output

For each test case, output two lines. The first line is an integer meaning the sum of scores.

The second line contains several integers separated by a space standing for the number of stones you pick. Print them by ascending order.

Sample Input

2
4 100
19 64
38 84
76 99
57 51
4 100
65 82
35 79
31 79
98 20

Sample Output

163
1 3
161
1 2

Hint

Output the minimum lexicographic scheme.

Source

哈理工2013春季校赛 - 现场赛

题意

01背包,有n个物品,让你选出其中的一些物品使总价值最大。
输出总价值,并且输出你选择的物品的编号。

思路

01背包+路径还原
01背包很简单,这里用二维数组记录每一步的背包内容。
01背包只有 拿和不拿两种情况。
所以我们只需要根据末尾状态去分别判断其是通过前一状态拿得来还是不拿得来,从而推出前一状态。
然后记录拿的状态的武平,最后输出一下就好。

AC代码

#include<bits/stdc++.h>
using namespace std;

int vis[106];
int dp[1006][1006];
int val[106],wei[106];

void solve(void)
{
    int n,m;
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(vis,0,sizeof vis);
        memset(dp,0,sizeof dp);
        scanf("%d%d",&n,&m);
        for(int i = 1 ; i <= n ; i++)
        {
            scanf("%d%d",&wei[i],&val[i]);
        }
        memset(dp,0,sizeof dp);
        for(int i = 1 ; i <= n ; i++)
        {
            for(int j = m ; j >= 0 ; j--)
            {
                if(j - wei[i] >= 0)
                    dp[i][j] = max(dp[i-1][j],dp[i-1][j-wei[i]] + val[i]);
                else
                    dp[i][j] = dp[i-1][j];
            }
        }
        int t = 0;
        printf("%d\n",dp[n][m]);
        for(int i = n ; i >= 1 ; i--)
        {
            if(dp[i][m]!=dp[i-1][m]) ///判断是前一状态的“不拿“的情况吗?
            {
                ///不是的话,那就是拿了这个物品,记录这个物品。
                vis[i] = 1;
                m-=wei[i]; ///重量减去这个物品的重量就可以找到前一个状态。
                t++;
            }
        }
        int flag = 0;
        for(int i = 1 ; i <= n ; i++)
        {
            if(vis[i]!=0)
            {
                printf("%d",i);
                flag++;
                if(flag==t)
                {
                    printf("\n");
                    break;
                }
                else
                    printf(" ");
            }
        }
    }
}

int main(void)
{
    solve();
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

两米长弦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值