51 nod CSP-J 模拟题 C航运中心

赛题-航运中心 (51nod.com)

题目描述

  1. 1.0 秒
  2. 262,144.0 KB
  3. 100 分

有 n 件行李(编号 1 到 n )以及 m 个箱子(编号 1 到 m )。第 i件行李的大小为 w[i] ,价值为 v[i] 。每个箱子只可以装一件行李,并且尺寸不能超过 x[i] 。

因为某种原因,箱子有时会变得不可用,有 q 个询问。每个查询给出两个整数 l和 r ,即从 l 到 r 号箱子不可用,请你回答,在这种情况下,剩余的箱子最多能够放下多少价值的行李。

收起

输入

第一行:3个数n,m,q,中间用空格分隔。
后面n行,每行2个数,对应n个箱子的 w[i] 和 v[i]。
之后一行共有m个数,表示箱子的容量。
之后q行,每行两个数 l,r 对应不可用箱子的范围。
其中1≤n,m,q≤50,1≤w[i],v[i],x[i]≤1000000。

输出

输出q行。每行一个询问的答案。

数据范围

对于100%的数据,

1≤n,m,q≤50; 1≤w[i],v[i],x[i]≤1000000; l≤r≤m。

输入样例

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

输出样例

20
0
9

解题思路:

这题看起来像是背包,实际上是贪心。我们对盒子排序后,从小到大逐个处理,对于每个盒子,让他拿到能装下的价值最高的行李。

由于盒子大小是有序的,因此对于后面的盒子,能装下的行李的数量是递增的。从小到大处理可以保证最终的方案最优。这样做的时间复杂度为 O ( m n q ) O(mnq) O(mnq)

如果用优先队列维护,则时间复杂度可以降为 O ( q m ( l o g ( n ) + l o g ( m ) ) ) O(qm(log(n)+log(m))) O(qm(log(n)+log(m))) 。其中 m l o g ( m ) mlog(m) mlog(m) 是对 m 个行李排序的复杂度,这部分还有优化的空间,我们可以通过一次排序,后面只是去掉范围在 (l,r) 的行李,这部分的平摊复杂度可以降为 O(m) ,总的时间复杂度为 $O(qm(log(n)))

#include <algorithm>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
int n, m, q;
bool used_good[100];
bool used_box[100];
struct good
{
    int v, w;
} a[100];

struct box
{
    int id;// 盒子的id
    int c; // 盒子的容量
} x[100];


// good 按照价值大的排前面。
bool cmp1(good a1, good a2)
{
    return a1.v > a2.v;
}

// box 按照体积的从小到大排。
bool cmp2(box a, box b)
{
    return a.c < b.c;
}

// 快读
inline int read()
{
    int x = 0, f = 1;
    char s = getchar();
    while (s < '0' || s > '9')
    {
        if (s == '-')
            f = -f;
        s = getchar();
    }
    while (s >= '0' && s <= '9')
    {
        x = (x << 3) + (x << 1) + (s ^ 48);
        s = getchar();
    }
    return x * f;
}

int main()
{
   cin >> n >> m >> q;
    for (int i = 1; i <= n; i++)
    {
        a[i].w = read();
        a[i].v = read();
    }
    for (int i = 1; i <= m; i++)
    {
        x[i].c = read();
        x[i].id = i; // box序号
    }
    // good 按照价值大的排前面。
    sort(a + 1, a + n + 1, cmp1);
    // box 按照体积的从小到大排。
    sort(x + 1, x + m + 1, cmp2);

    while (q--)
    {
        // q次问询,开始进行初始化
        int l = read(), r = read();
        int ans = 0;
        memset(used_good, 0, sizeof used_good);
        memset(used_box, 0, sizeof used_box);

        // 从小到大遍历box,
        for (int i = 1; i <= m; i++)
        {
            // 不能用的盒子跳过
            if (l <= x[i].id && x[i].id <= r)
                continue; 
			// 物品价值从大到小排列
            for (int j = 1; j <= n; j++)
            {
                // 找到第一个能装的下的最价值的物品后跳出。
                if (x[i].c >= a[j].w && !used_good[j] && !used_box[i])
                {
                    ans += a[j].v;
                    used_good[j] = 1; // 标记物品使用过了。
                    used_box[i] = 1;  // 标记盒子被使用了。
                    continue;
                }
            }
        }
        cout << ans << endl;
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值