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

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;
}

猜你喜欢

转载自blog.csdn.net/peng0614/article/details/81272794
今日推荐