【ACWing】1013. 机器分配

题目地址:

https://www.acwing.com/problem/content/1015/

总公司拥有 M M M台相同的高效设备,准备分给下属的 N N N个分公司。各分公司若获得这些设备,可以为国家提供一定的盈利。盈利与分配的设备数量有关。问:如何分配这 M M M台设备才能使国家得到的盈利最大?求出最大盈利值。分配原则:每个公司有权获得任意数目的设备,但总台数不超过设备数 M M M

输入格式:
第一行有两个数,第一个数是分公司数 N N N,第二个数是设备台数 M M M;接下来是一个 N ∗ M N*M NM的矩阵,矩阵中的第 i i i行第 j j j列的整数表示第 i i i个公司分配 j j j台机器时的盈利。

输出格式:
第一行输出最大盈利值;接下 N N N行,每行有 2 2 2个数,即分公司编号和该分公司获得设备台数。答案不唯一,输入任意合法方案即可。

数据范围:
1 ≤ N ≤ 10 1≤N≤10 1N10
1 ≤ M ≤ 15 1≤M≤15 1M15

可以想象这 N N N个公司是 N N N组不同的物品,每组物品里有 M M M个不同的物品,体积分别是 1 , 2 , . . . , M 1,2,...,M 1,2,...,M,并且有不同的价值。那么可以看成是分组背包问题,在总体积限制是 M M M的情况下求最大价值。关于分组背包问题的思路,参考https://blog.csdn.net/qq_46105170/article/details/113845540。求方案的时候,只需逆着推一遍即可。代码如下:

#include <iostream>
using namespace std;

const int N = 11, M = 16;
int n, m;
int w[N][M];
int f[N][M];
int way[N];

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

    for (int i = 1; i <= n; i++)
        for (int j = 0; j <= m; j++) {
        	// 枚举第i组物品不选的情形
            f[i][j] = f[i - 1][j];
            // 枚举第i组物品选第k个的情形,其实每个物品的体积就是k
            for (int k = 1; k <= j; k++) {
                f[i][j] = max(f[i][j], f[i - 1][j - k] + w[i][k]);
            }
        }

    cout << f[n][m] << endl;

    for (int i = n, j = m; i >= 1; i--) 
        for (int k = 0; k <= j; k++)
            if (f[i][j] == f[i - 1][j - k] + w[i][k]) {
                way[i] = k;
                j -= k;
                break;
            }

    for (int i = 1; i <= n; i++) 
        printf("%d %d\n", i, way[i]);

    return 0;
}

时空复杂度 O ( N M 2 ) O(NM^2) O(NM2)

题目链接:https://www.acwing.com/problem/content/4948/ 题目描述: 给定一棵有 $n$ 个结点的树,结点从 $1$ 到 $n$ 编号,每个结点都有一个权值 $w_i$,现在有 $m$ 次操作,每次操作是将树中编号为 $x$ 的结点的权值加上 $y$,然后询问一些节点是否为叶子节点,如果是输出 $1$,否则输出 $0$。 输入格式: 第一行包含两个整数 $n$ 和 $m$。 第二行包含 $n$ 个整数,其中第 $i$ 个整数表示结点 $i$ 的初始权值 $w_i$。 接下来 $n-1$ 行,每行包含两个整数 $a$ 和 $b$,表示点 $a$ 和点 $b$ 之间有一条无向边。 接下来 $m$ 行,每行描述一次操作,格式为三个整数 $t,x,y$。其中 $t$ 表示操作类型,$t=1$ 时表示将编号为 $x$ 的结点的权值加上 $y$,$t=2$ 时表示询问编号为 $x$ 的结点是否为叶子节点。 输出格式: 对于每个操作 $t=2$,输出一个结果,表示询问的结点是否为叶子节点。 数据范围: $1≤n,m≤10^5$, $1≤w_i,y≤10^9$ 样例: 输入: 5 5 1 2 3 4 5 1 2 1 3 3 4 3 5 2 3 0 1 3 100 2 3 0 1 1 100 2 3 0 输出: 1 0 0 算法1: 暴力dfs,每次都重新遍历整棵树,时间复杂度 $O(nm)$ 时间复杂度: 最坏情况下,每次操作都要遍历整棵树,时间复杂度 $O(nm)$,无法通过此题。 算法2: 用一个 vector<int> sons[n+5] 来存储每个点的所有子节点,这样可以用 $O(n)$ 预处理出每个点的度数 $deg_i$,如果 $deg_i=0$,则 $i$ 是叶子节点,否则不是。 对于每个操作,只需要更新叶子节点关系的变化就可以了。如果某个节点的度数从 $1$ 变成 $0$,则该节点变成了叶子节点;如果某个节点的度数从 $0$ 变成 $1$,则该节点不再是叶子节点。 时间复杂度: 每次操作的时间复杂度是 $O(1)$,总时间复杂度 $O(m)$,可以通过此题。 C++ 代码: (算法2)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值