总结背包问题(不同数据范围下)

1.普通情况

采药

辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。

为此,他想拜附近最有威望的医师为师。

医师为了判断他的资质,给他出了一个难题。

医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。”

如果你是辰辰,你能完成这个任务吗?

输入格式

输入文件的第一行有两个整数 T 和 M,用一个空格隔开,T 代表总共能够用来采药的时间,MM 代表山洞里的草药的数目。

接下来的 M 行每行包括两个在 1 到 100 之间(包括 1 和 100)的整数,分别表示采摘某株草药的时间和这株草药的价值。

输出格式

输出文件包括一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。

数据范围

1≤T≤1000,
1≤M≤100

输入样例:

70 3
71 100
69 1
1 2

输出样例:

3
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int t,m,i,j;
ll dp[1005];
ll w[105],v[105];
int main()
{
       scanf("%d%d",&t,&m);
       for(i=1;i<=m;i++)
       {
           scanf("%d%d",&w[i],&v[i]);
       }
    for(int i=1;i<=m;i++)
    {
        for(int j=t;j>=w[i];j--)
        {
            dp[j]=max(dp[j],dp[j-w[i]]+v[i]);
        }
    }
    cout<<dp[t]<<endl;


    return 0;
}

2.体积大价值小

题目描述

给定 n 个物品,每个物品的价值为 vi​,重量为 wi​,请从这些物品中选出一些,在它们的重量之和不超过一个给定值 c 的前提下,价值之和达到最大。

注意本题中物品的重量可能比较大。

输入格式

第一行:两个整数 n 与 c。
第二行到第 n+1 行,第 i+1 行有两个整数表示 vi​ 与 wi​

输出格式

单个整数:表示满足限定条件下的最大价值和。

数据范围

  • 对于 30% 的数据, n≤20;
  • 对于 60% 的数据, c≤10000;
  • 对于 100% 的数据, 1≤n≤500,1≤c≤10^18,1≤vi​≤500,1≤wi​≤10^18。

样例数据

输入:

3 1000
90 900
53 550
38 400

输出:

91

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=510;
int v[N],w[N],n,c;
int sum;
int dp[N*N];
signed main()
{
    cin>>n>>c;

    for(int i=1; i<=n; i++)
    {
        cin>>v[i]>>w[i];

        sum+=v[i];
    }
    memset(dp,0x3f,sizeof dp);
    dp[0]=0;
    for(int i=1; i<=n; i++)
    {
        for(int j=sum; j>=v[i]; j--)
        {
            dp[j]=min(dp[j],dp[j-v[i]]+w[i]);
        }
    }


    for(int i=sum; i>=0; i--)
    {
        if(dp[i]!=0x3f3f3f3f&&dp[i]<=c)
        {
            cout<<i<<"\n";
            return 0;
        }
    }







    return 0;
}

数据可能有点水,0x3f还是有点小感觉

3.价值和体积都很大,搜索

 小奇采药

题目描述

小奇是只天资聪颖的喵,他的梦想是成为世界上最伟⼤的医师。
为此,他想拜喵星球最有威望的医师为师。
医师为了判断他的资质,给他出了⼀个难题。
医师把他带到⼀个到处都是草药的⼭洞里对他说:“小奇,这个⼭洞里有⼀些不同的草药,采每⼀株都需要⼀些时间,每⼀株也有它自身的价值。
我会给你⼀段时间,在这段时间里,你可以采到⼀些草药。
如果你是⼀只聪明的喵,你应该可以让采到的草药的总价值最⼤。”

输入

第R⾏包括R个整数h,表示数据组数。
对于每组数据,第R⾏包括k个整数,M,K,表示草药的数目和能用于采药的时间。
接下来M⾏,每⾏两个整数ti,vi。
保证m,ti,vi在限制范围内均匀随机⽣成。

输出

输出h⾏,每⾏R个数字,表示每组数据答案。

样例输入

1
3 70
71 100
69 1
1 2

样例输出 

3

提示

对于30%数据,1≤n≤20,1≤m,vi,ti≤10^4
对于60%数据,1≤n≤100,1≤m,vi,ti≤10^5
对于100%数据,1≤T≤10,1≤n≤150,1≤m,vi,ti≤10^9

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll st[155],sv[155];
ll t,n,m,ans;
struct node
{
    ll times,value;
}s[155];
bool cmp(node a,node b)
{
    return a.times>b.times;
}
void dfs(ll x,ll sumt,ll sumv)
{
    ans=max(ans,sumv);
    if(sumt+s[n].times>m)return;
    if(sumv+sv[x]<ans)return ;
    if(sumt+st[x]<=m)
    {
        ans=max(ans,sumv+sv[x]);
        return ;
    }
    if(sumt+s[x].times<=m)dfs(x+1,sumt+s[x].times,sumv+s[x].value);
        dfs(x+1,sumt,sumv);
}
int main()
{
   scanf("%lld",&t);
   while(t--)
   {
       scanf("%lld%lld",&n,&m);
       for(int i=1;i<=n;i++)scanf("%lld%lld",&s[i].times,&s[i].value);
       sort(s+1,s+1+n,cmp);
       for(int i=n;i>=1;i--)
       {
           st[i]=st[i+1]+s[i].times;
           sv[i]=sv[i+1]+s[i].value;
       }
       ans=0;
       dfs(1,0,0);
       printf("%lld\n",ans);
   }
 
 
 
    return 0;
}

4.双向搜索

送礼物

达达帮翰翰给女生送礼物,翰翰一共准备了 N 个礼物,其中第 i 个礼物的重量是G[i]。

达达的力气很大,他一次可以搬动重量之和不超过 W 的任意多个物品。

达达希望一次搬掉尽量重的一些物品,请你告诉达达在他的力气范围内一次性能搬动的最大重量是多少。

输入格式

第一行两个整数,分别代表 W 和 N。

以后 NN 行,每行一个正整数表示 G[i]。

输出格式

仅一个整数,表示达达在他的力气范围内一次性能搬动的最大重量。

数据范围

1≤N≤46
1≤W,G[i]≤2^31−1

输入样例:

20 5
7
5
4
18
1

输出样例:

19

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1 << 24;
int n, m, k;
int g[50], weights[N];
int cnt = 0;
int ans;


void dfs(int u, int s)
{
    if (u == k)
    {
        weights[cnt ++ ] = s;
        return;
    }

    if ((LL)s + g[u] <= m) dfs(u + 1, s + g[u]);
    dfs(u + 1, s);
}


void dfs2(int u, int s)
{
    if (u == n)
    {
        int l = 0, r = cnt - 1;
        while (l < r)
        {
            int mid = l + r + 1 >> 1;
            if (weights[mid] + (LL)s <= m) l = mid;
            else r = mid - 1;
        }
        if (weights[l] + (LL)s <= m) ans = max(ans, weights[l] + s);

        return;
    }

    if ((LL)s + g[u] <= m) dfs2(u + 1, s + g[u]);
    dfs2(u + 1, s);
}


int main()
{
    cin >> m >> n;
    for (int i = 0; i < n; i ++ ) cin >> g[i];

    sort(g, g + n);
    reverse(g, g + n);

    k = n / 2; 
    dfs(0, 0);

    sort(weights, weights + cnt);
    int t = 1;
    for (int i = 1; i < cnt; i ++ )
        if (weights[i] != weights[i - 1])
            weights[t ++ ] = weights[i];
    cnt = t;

    dfs2(k, 0);

    cout << ans << endl;

    return 0;
}

总结到此为止,仅用于记录

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值