Vj程序设计作业H12

A : 01背包

题目描述

有 N 件物品和一个容量为 V 的背包。第 i 件物品的重量是 w[i],价值是 c[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

输入描述

第一行为 N(1≤N≤5000),V(1≤V≤5000)。

下面 N 行,第 i 行描述第 i 个物品的 w[i](1≤w[i]≤103),c[i](1≤c[i]≤103),用一个空格分隔。

输出描述

输出只有一个数,最大总价值。

测试样例

样例 1

输入:

10 9
7 1
8 10
7 10
7 7
7 6
3 7
4 1
3 3
9 1
1 4

 

输出:

14

解答

#include<bits/stdc++.h>

using namespace std;

int main(){
    int N, V;
    cin >> N >> V;
    int w[N+1], c[N+1];
    for (int i = 1; i <= N;i++){
        cin >> w[i] >> c[i];
    }
    int f[N+1][V+1];
    for (int i = 0; i <= N;i++){
        for (int j = 0; j <= V;j++){
            f[i][j] = 0;
        }
    }
        for (int i = 1; i <= N; i++)
        {
            for (int j = 1; j <= V;j++)
            if(j>=w[i])
                f[i][j] = max(f[i - 1][j], f[i - 1][j - w[i]] + c[i]);
            else
                f[i][j] = f[i - 1][j];
        }
    cout << f[N][V] << endl;
    return 0;
}

B : 完全背包

题目描述

有 N 种物品(每种有无限多个)和一个容量为 V 的背包。第 i 种物品的重量是 w[i],价值是 c[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

输入描述

第一行为 N(1≤N≤5000),V(1≤V≤5000)。

下面 N 行,第 i 行描述第 i 种物品的 w[i](1≤w[i]≤103),c[i](1≤c[i]≤103),用一个空格分隔。

输出描述

输出只有一个数,最大总价值。

测试样例

样例 1

输入:

10 8
4 5
1 1
1 5
5 4
5 10
6 5
1 1
5 6
7 4
4 5

输出:

40

解答

#include<bits/stdc++.h>

using namespace std;

int main(){
    int N, V;
    cin >> N >> V;
    int w[N+1], c[N+1];
    for (int i = 1; i <= N;i++){
        cin >> w[i] >> c[i];
    }
    int f[N+1][V+1];
    int x = 0;
    for (int i = 0; i <= N;i++){
        for (int j = 0; j <= V;j++){
            f[i][j] = 0;
        }
    }
        for (int i = 1; i <= N; i++)
        {
            for (int j = 1; j <= V;j++){
                int y = 0;
                for (int k = 1; k <= V / w[i];k++){
                    if(j>=k*w[i]){
                        x = f[i - 1][j - k * w[i]] + k*c[i];
                        y = max(x, y);
                    }
                }
                int s = f[i - 1][j];
                f[i][j] = max(y, s);
            }
        }
    cout << f[N][V] << endl;
    return 0;
}

C : 多重背包

多重背包

题目描述

有 N 种物品和一个容量为 V 的背包。第 i 种物品的重量是 w[i],价值是 c[i],有 k[i]个。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

输入描述

第一行为 N(1≤N≤104),V(1≤V≤104)。

下面 N 行,第 i 行描述第 i 种物品的 w[i](1≤w[i]≤102),c[i](1≤c[i]≤106),k[i](1≤k[i]≤102),用一个空格分隔。

输出描述

输出只有一个数,最大总价值。

测试样例

样例 1

输入:

6 1
7 10 4
6 9 1
6 8 1
10 6 2
9 8 3
1 3 2

输出:

3

解答

#include<bits/stdc++.h>

using namespace std;
#define ll long long
ll tot;
ll N, V;
ll w[1000000],v[1000000];
void addItem(ll x, ll y){
    w[tot] = x;
    v[tot] = y;
    tot++;
}

void init(){
    tot = 1;
}
int main(){
    cin >> N >> V;
    // ll c[N+1],g[N+2];
    init();
    ll weight, value, count;
    for (int i = 1; i <= N;i++){
        cin >> weight >> value >> count;
        for (int i = 1; i <= count; i *= 2){
            addItem(weight * i, value * i);
            count -= i;
        }
        if(count>0){
            addItem(weight * count, value * count);
        }
    }
    ll f[2][V+1];
    for (int i = 0; i < 2;i++){
        for (int j = 0; j <= V;j++){
            f[i][j] = 0;
        }    
    }
        for (int i = 1; i < tot; i++)
        {
            for (int j = 1; j <= V; j++)
            {
                f[i & 1][j] = f[(i - 1) & 1][j];
                if (j >= w[i])
                {
                    f[i & 1][j] = max(f[(i - 1) & 1][j], f[(i - 1) & 1][j - w[i]] + v[i]);
                }
            }
        }
    cout << f[(tot - 1) & 1][V]<<endl;
    return 0;
}

D : 分组背包

分组背包

题目描述

有 N 件物品和一个容量为 V 的背包,将所有的物品划分成若干组,每个组里面的物品最多选一件。第 i 件物品的重量是 w[i],价值是 c[i],属于组 k[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

输入描述

第一行为 N(1≤N≤103),V(1≤V≤103)。

下面 N 行,第 i 行描述第 i 个物品的 w[i](1≤w[i]≤102),c[i](1≤c[i]≤106),k[i](1≤k[i]≤102),用一个空格分隔。

输出描述

输出只有一个数,最大总价值。

测试样例

样例 1

输入:

7 9
6 6 3
5 10 3
3 5 1
9 4 4
6 1 4
8 3 5
5 2 2

输出:

15

解答

#include<bits/stdc++.h>

using namespace std;
#define ll long long
ll N, V;
ll w[1000000], v[10000010];
ll tot;

// vector<ll> group;
ll group[101][1001];
ll a[101]; // 记录每一维group的最后一位
void init(){
    for (int i = 0; i <= N;i++){
        w[i] = 0;
        v[i] = 0;
        // groups[i].k = 0;/??//
    }
    tot = 0;
    for (int i = 0; i <= 100;i++){
        for (int j = 0; j <= 1000;j++){
            group[i][j] = 0;
        }
    }
    for (int i = 1; i <= 100;i++){
        a[i] = 1;
    }
}


int main(){
    cin >> N >> V;
    int x, y, z;
    init();
    for (int i = 1; i <= N;i++){
        cin >> x >> y >> z;
        w[i] = x;
        v[i] = y;
        if(group[z][1]==0){
            tot++;
        }
        group[z][a[z]] = i;
        a[z]++;
    }
    ll f[V + 1];
    for (int i = 0; i <= V;i++){
        f[i] = 0;
    }
        for (int i = 1; i <= 100; i++)
        {
            for (int j = V; j >= 1; j--)
            {
                for (int k : group[i])
                {
                    if (j >= w[k])
                    {
                        f[j] = max(f[j], f[j - w[k]] + v[k]);
                    }
                }
            }
        }
    cout << f[V] << endl;
    return 0;
}

E : 超大背包

题目描述

有 N 件物品和一个容量为 V 的背包。第 i 件物品的重量是 w[i],价值是 c[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。

输入描述

第一行为 N(1≤N≤40),V(1≤V≤1015)。

下面 N 行,第 i 行描述第 i 个物品的 w[i](1≤w[i]≤1015),c[i](1≤c[i]≤1015),用一个空格分隔。

输出描述

输出只有一个数,最大总价值。

测试样例

样例 1

输入:

3 225274242
70498827 830583485
72910089 759360759
80945586 1095298545

输出:

2685242789

样例 2

输入:

27 1405406868
500580317 1559925714
1191095816 2052289019
2086671060 125049457
1467200227 1826963529
1054830291 1055178046
457445390 293196664
1428828824 1163887408
27108927 353186119
354284919 1641947343
1044113045 1319050872
814300917 42212882
802287458 2142953934
1178508095 943859578
2133693898 163905627
1687820729 1091482274
737249638 2121489517
1203304272 1081378899
581034126 832395967
1370524005 487337507
178833685 1328104836
512934928 897959032
1629846549 1677014752
2011536830 64430283
547991487 1683026867
2125422226 728351378
744805340 261154211
1909716650 317131682

输出:

5466192232

解答

#include <iostream>
#include <cmath>
#include <algorithm>
#define inf 0x3f3f3f3f3f3f3f3f
using namespace std;
const int Max = 42;
typedef long long ll;
ll w[Max], v[Max];
ll N, W; 
pair<ll, ll> arr[1 << (Max / 2)];  //重量,价值
pair<ll, ll> arr2[1 << (Max / 2)];  //重量,价值
pair<ll, ll> temp[1 << Max / 2];
ll ans = 0;

bool cmp(pair<ll, ll>& a, pair<ll, ll>& b)
{
	return a.second < b.second;
}

void solve()
{
	ll n = N / 2;
	for (ll i = 0; i < (1 << n); i++)
	{
		ll now_w = 0, now_v = 0;
		for (int j = 0; j < n; j++)
		{
			if (i >> j & 1)   //对于二进制数i,它的第j位是1
			{
				now_w += w[j];
				now_v += v[j];
			}
		}
		arr[i].first = now_w;    //二进制数i表示当前选中的状态,对这个状态来计算当前的价值和重量
		arr[i].second = now_v;
	}

	sort(arr, arr + (1 << n));     //第一维升序
	ll current_min = arr[0].second;
	ll j = 0;
	// 进行部分数据剔除
	for (ll i = 1; i < pow(2, n); i++)
	{
		if (arr[i].second > current_min)
			arr2[j++] = arr[i];
		else
			current_min = arr[i].second;
	}
	// 第二部分的选择,同时进行判断最大的值
	for (ll i = 0; i < (1 << (N - n)); i++)
	{
		ll now_w = 0, now_v = 0;
		for (ll k = 0; k < (N - n); k++)
		{
			if ((i >> k) & 1)
			{
				now_w += w[n + k];
				now_v += v[n + k];
			}
		}
		if (now_w <= W)
		{
			ll v = 0;
			for (ll s = j - 1; s >= 0; s--)
			{
				if (arr2[s].first <= W - now_w)   //在符合重量要求的前提下找最大重量
				{
					for (int p = 0; p <= s; p++)
						temp[p] = arr2[p];
					sort(temp, temp + s + 1, cmp);
					v = temp[s].second;
					break;
				}
			}
			//cout << "v = " << v << endl;
			ans = max(ans, v + now_v);
		}
	}
}

int main()
{
	cin >> N >> W;
	for (ll i = 0; i < N; i++)
		cin >> w[i] >> v[i];
	solve();
	cout << ans << endl;


	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值