hrbust/哈理工oj 1740 A Story on a Sunshine Beach【二维01背包+输出路径】

A Story on a Sunshine Beach
Time Limit: 1000 MSMemory Limit: 65535 K
Total Submit: 113(33 users)Total Accepted: 35(26 users)Rating: Special Judge: No
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 Output1631 31611 2
 
Hint

Output the minimum lexicographic scheme.

Source
哈理工2013春季校赛 - 现场赛
题目大意:

有n个石头,给你一个容量值为v的一个背包,每个石头都有其价值和容量值,问最多放多少价值的石头,并且输出拿的石头的编号,并且要求字典序最小。

思路:一看就知道是01背包的问题,输出dp路径一直是很火的一种变形,这个题也不例外。


对于二维处理01背包,如果从1到n的动态转移我们需要从n到1的寻找路径,但是因为输出要求字典序最小,所以我们要从n到1的动态转移,然后就能从1到n的寻找路径了。


对于状态转移方程:dp[i][j]=max(dp[i+1][j-cost[i]]+val[i],dp[i][j]);辣么对于寻找路径,我们直接遍历从1到n,如果dp[i][v]==dp[i+1][v-cost[i]]+val[i],那么这个i就是在路径中选择了的一个石头,对应v-=cost[i],然后继续向下找下一块石头。


AC代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int cost[10000];
int val[10000];
int dp[1000][10000];
int ans[1000];
void solve(int n,int v)
{
    memset(dp,0,sizeof(dp));
    for(int i=n;i>=1;i--)
    {
        for(int j=0;j<=v;j++)
        {
            if(i==n)dp[i][j]=0;
            else dp[i][j]=dp[i+1][j];
            if(j>=cost[i]&&dp[i][j]<dp[i+1][j-cost[i]]+val[i])
            dp[i][j]=dp[i+1][j-cost[i]]+val[i];
        }
    }
    int cont=0;
    printf("%d\n",dp[1][v]);
    for(int i=1;i<=n;i++)
    {
        if(dp[i][v]==dp[i+1][v-cost[i]]+val[i])
        {
            ans[cont]=i;
            cont++;
            v-=cost[i];
        }
    }
    int f=0;
    for(int i=0;i<cont;i++)
    {
        if(f==0)
        printf("%d",ans[i]);
        else 
        printf(" %d",ans[i]);
        f++;
    }
    printf("\n");
}
int main()
{
    int t;
    while(~scanf("%d",&t))
    {
        while(t--)
        {
            int n,m;
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++)
            {
                scanf("%d%d",&cost[i],&val[i]);
            }
            solve(n,m);
        }
    }
}









  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值