0/1背包及其延申延伸

0/1背包
Many years ago , in Teddy’s hometown there was a man who was called “Bone Collector”. This man like to collect varies of bones , such as dog’s , cow’s , also he went to the grave …
The bone collector had a big bag with a volume of V ,and along his trip of collecting there are a lot of bones , obviously , different bone has different value and different volume, now given the each bone’s value along his trip , can you calculate out the maximum of the total value the bone collector can get ?
INPUT
The first line contain a integer T , the number of cases.
Followed by T cases , each case three lines , the first line contain two integer N , V, (N <= 1000 , V <= 1000 )representing the number of bones and the volume of his bag. And the second line contain N integers representing the value of each bone. The third line contain N integers representing the volume of each bone.
OUTPUT
One integer per line representing the maximum of the total value (this number will be less than 231).
题意:n个物品,有其价值与重量,给一个容量为m的背包,问在不超过背包容量的情况下,能装物品的最大价值。
最基本的0/1背包,直接看代码。

#include <iostream>
#include <cmath>
#include <stdio.h>
#include <vector>
#include <algorithm>
#include<cstring>
using namespace std;

int main()
{
    int t;
    cin>>t;
    int x[1001];
    int y[1001];
    int dp[10000];
    while(t--)
    {
        int n,m;
        cin>>n>>m;
        for(int i = 0; i <= m; i++)
        {
            dp[i] = 0;
        }
        for(int a=0;a<n;a++)
            cin>>x[a];
        for(int a=0;a<n;a++)
            cin>>y[a];
        for(int a=0;a<n;a++)
            {
                for(int v=m;v>=y[a];v--)
                {
                    dp[v]=max(dp[v],dp[v-y[a]]+x[a]);
                }
            }
            cout<<dp[m]<<endl;
    }
    return 0;
}

最简单的0/1背包给出背包容量,每件物品有自己的价值,最好理解。

延伸
1、0/1背包延伸的概率问题
The aspiring Roy the Robber has seen a lot of American movies, and knows that the bad guys usually gets caught in the end, often because they become too greedy. He has decided to work in the lucrative business of bank robbery only for a short while, before retiring to a comfortable job at a university.
在这里插入图片描述

For a few months now, Roy has been assessing the security of various banks and the amount of cash they hold. He wants to make a calculated risk, and grab as much money as possible.

His mother, Ola, has decided upon a tolerable probability of getting caught. She feels that he is safe enough if the banks he robs together give a probability less than this.

题意:小偷去银行偷钱,给出他能偷得银行数n和他被抓的总概率m。n个银行每个银行有能得到的钱数x【i】以及没个银行被抓的概率。问在不被抓的情况下小偷能得到的最多的钱数。

刚开始做的时候以为这是简单的0/1背包问题,以被抓的总概率当做背包容量,每个银行的钱数当做价值,提交后发现不对。
这样想明显是错误的,因为如果偷第i家银行不被抓,那么偷第i-1家银行时也不能被抓,这就变成了概率相乘的问题,而不是相加。

解题思路:我们可以把所有银行的钱数之和当做背包容量,求偷sum钱时不被抓的概率,然后再将钱数从大到小找出最大的不被抓的那个钱数就是最多能偷的钱数。

#include <iostream>
#include <cmath>
#include <stdio.h>
#include <vector>
#include <algorithm>
#include<cstring>
#define ll 0x3f3f3f
using namespace std;


double y[101];
int x[101];
double dp[10001];
int main()
{
	int t;
	cin>>t;
	while(t--)
    {
        memset(dp,0,sizeof(dp));
        dp[0]=1;
        double m;
        int n;
        cin>>m>>n;
        m=1-m;
        int sum=0;
        for(int a=0;a<n;a++)
            {cin>>x[a]>>y[a];sum+=x[a];}
            for(int a=0;a<n;a++)
                for(int v=sum;v>=x[a];v--)
                dp[v]=max(dp[v],dp[v-x[a]]*(1-y[a]));
            for(int a=sum;a>=0;a--)
                if(dp[a]>=m)
            {
                cout<<a<<endl;
                break;
            }
    }
	return 0;
}

概率背包将偷到的钱数当作背包容量,以不被抓的概率当作获得的价值。
2、0/1背包延伸的方案数问题
When the winter holiday comes, a lot of people will have a trip. Generally, there are a lot of souvenirs to sell, and sometimes the travelers will buy some ones with pleasure. Not only can they give the souvenirs to their friends and families as gifts, but also can the souvenirs leave them good recollections. All in all, the prices of souvenirs are not very dear, and the souvenirs are also very lovable and interesting. But the money the people have is under the control. They can’t buy a lot, but only a few. So after they admire all the souvenirs, they decide to buy some ones, and they have many combinations to select, but there are no two ones with the same kind in any combination. Now there is a blank written by the names and prices of the souvenirs, as a top coder all around the world, you should calculate how many selections you have, and any selection owns the most kinds of different souvenirs. For instance:
在这里插入图片描述

And you have only 7 RMB, this time you can select any combination with 3 kinds of souvenirs at most, so the selections of 3 kinds of souvenirs are ABC (6), ABD (7). But if you have 8 RMB, the selections with the most kinds of souvenirs are ABC (6), ABD (7), ACD (8), and if you have 10 RMB, there is only one selection with the most kinds of souvenirs to you: ABCD (10).

题意:给出n个物品,每件物品有自己的价值,小明有m块钱,问小明能买最多物品件数的最多方案数。

解题思路:
**1、分两种情况,当买第i件物品的价值与不买第i件物品的价值相同时,总方案数=买第i件物品的方案数+不买第i件物品的方案数。
2、当买第i件物品的价值大于不买第i件物品价值时,总方案数=买第i件物品的方案数,同时更新买第i件物品的价值。**

#include <iostream>
#include <cmath>
#include <stdio.h>
#include <vector>
#include <algorithm>
#include<cstring>
#define ll 0x3f3f3f
using namespace std;


int y[101];//每件物品的价值,均为1
int x[101];//每件物品的重量
int dp[10001];//选中物品的个数,也相当于价值
int ans[10001];//方案数,ans[i]代表当剩余i元钱时能够选择的方案数
int main()
{
	int t;
	cin>>t;
	while(t--)
    {
        int n,m;
        cin>>n>>m;
        for(int a=0;a<n;a++)
            cin>>x[a];
            for(int a=0;a<=m;a++)
                ans[a]=1;
        for(int a=0;a<n;a++)
            y[a]=1;
        memset(dp,0,sizeof(dp));
        for(int a=0;a<n;a++)
            for(int v=m;v>=x[a];v--)
        {
            if(dp[v]==dp[v-x[a]]+y[a])//选择第a件物品的价值与不选第a件物品的价值相同时
                ans[v]+=ans[v-x[a]];//总方案数等于两者相加
                else if(dp[v]<dp[v-x[a]]+y[a])
                {
                    dp[v]=dp[v-x[a]]+y[a];//更新价值,找最大
                    ans[v]=ans[v-x[a]];
                }
        }
        if(dp[m]==0)cout<<"Sorry, you can't buy anything."<<endl;
        else
        cout<<"You have "<<ans[m]<<" selection(s) to buy with "<<dp[m]<<" kind(s) of souvenirs."<<endl;
    }
	return 0;
}

这个也属于最简单的0/1背包,只不过让求的时方案数,背包容量以及价值与最简单的0/1背包相同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值