【LuoGU 1273】有线电视网——树上分组背包问题

这篇具有很好参考价值的文章主要介绍了【LuoGU 1273】有线电视网——树上分组背包问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

有线电视网

题目描述

某收费有线电视网计划转播一场重要的足球比赛。他们的转播网和用户终端构成一棵树状结构,这棵树的根结点位于足球比赛的现场,树叶为各个用户终端,其他中转站为该树的内部节点。

从转播站到转播站以及从转播站到所有用户终端的信号传输费用都是已知的,一场转播的总费用等于传输信号的费用总和。

现在每个用户都准备了一笔费用想观看这场精彩的足球比赛,有线电视网有权决定给哪些用户提供信号而不给哪些用户提供信号。

写一个程序找出一个方案使得有线电视网在不亏本的情况下使观看转播的用户尽可能多。

输入格式

输入文件的第一行包含两个用空格隔开的整数 \(N\)\(M\),其中 \(2 \le N \le 3000\)\(1 \le M \le N-1\)\(N\) 为整个有线电视网的结点总数,\(M\) 为用户终端的数量。

第一个转播站即树的根结点编号为 \(1\),其他的转播站编号为 \(2\)\(N-M\),用户终端编号为 \(N-M+1\)\(N\)

接下来的 \(N-M\) 行每行表示—个转播站的数据,第 \(i+1\) 行表示第 \(i\) 个转播站的数据,其格式如下:

\(K \ \ A_1 \ \ C_1 \ \ A_2 \ \ C_2 \ \ \ldots \ \ A_k \ \ C_k\)

\(K\) 表示该转播站下接 \(K\) 个结点(转播站或用户),每个结点对应一对整数 \(A\)\(C\)\(A\) 表示结点编号,\(C\) 表示从当前转播站传输信号到结点 \(A\) 的费用。最后一行依次表示所有用户为观看比赛而准备支付的钱数。单次传输成本和用户愿意交的费用均不超过 10。

输出格式

输出文件仅一行,包含一个整数,表示上述问题所要求的最大用户数。

样例 #1

样例输入 #1

5 3
2 2 2 5 3
2 3 2 4 3
3 4 2

样例输出 #1

2

提示

样例解释

如图所示,共有五个结点。结点 ① 为根结点,即现场直播站,② 为一个中转站,③④⑤ 为用户端,共 \(M\) 个,编号从 \(N-M+1\)\(N\),他们为观看比赛分别准备的钱数为 \(3\)\(4\)\(2\)

从结点 ① 可以传送信号到结点 ②,费用为 \(2\)

也可以传送信号到结点 ⑤,费用为 \(3\)(第二行数据所示);

从结点 ② 可以传输信号到结点 ③,费用为\(2\)

也可传输信号到结点 ④,费用为 \(3\)(第三行数据所示)。

如果要让所有用户(③④⑤)都能看上比赛,则信号传输的总费用为:\(2+3+2+3=10\),大于用户愿意支付的总费用 \(3+4+2=9\),有线电视网就亏本了,而只让 ③④ 两个用户看比赛就不亏本了。

解法

注意到本题的特征:从若干个物品中选出一些来满足某一个限制条件,符合背包问题的特征,因此我们可以从背包问题出发思考。
题目中要选择的目标是树的叶子节点,由于叶节点被子树分成了若干个组,因此这个问题就是一个分组背包问题:
分组背包问题模板(滚动数组优化版本)

for(int i = 1; i <= n; i ++ ){    //组数
        for(int j = V; j >= 0; j -- ){     //背包容量
            for(int k = 0; k <= sz[i]; k ++ ){          //枚举每一组中的物品
                int vik = v[i][k], wik = w[i][k];
                if(j >= vik) f[j] = std::max(f[j], f[j - vik] + wik);
            }
        }
    }

\(f[u][i][j]\)表示结点\(u\)的前\(i\)个儿子中选择\(j\)个结点的最大利润。我们考虑最后一个分界点:如果不取第\(i\)个结点,则状态转移为$$f[u][i][j] = f[u][i - 1][j]$$如果取第\(i\)个结点,记为\(v\),那么状态转移方程为$$f[u][i][j] = f[u][i - 1][j - k] + f[v][sz[v]][k] - w_{u, v}$$其中\(sz[v]\)表示\(v\)的子树大小,\(k\)表示从\(v\)的子树中选择的节点个数,\(w_{u, v}\)\(u,v\)之间的花费.所以最终的状态转移方程为$$f[u][i][j] = max_{v \in son[u]}(f[u][i-1][j], f[u][i-1][j-k]+f[v][sz[v]][k] - w_{u,v})$$
显然根据\(0/1\)背包的思想我们可以对上式进行空间优化,只需要在枚举选择的节点个数时倒序枚举即可。优化后的状态转移方程为$$f[u][j] = max_{v \in son[u]}(f[u][j], f[u][j - k] + f[v][k] - w_{u, v})$$
注意本题最终问的问题,是要在不亏本的情况下能够观看转播的最多用户数,也就是满足\(f[1][j] \geq 0\)的最大的\(j\),因此在做完后需要从大到小枚举\(j\)来找到答案。文章来源地址https://www.toymoban.com/news/detail-597203.html

#include<bits/stdc++.h>

const int N = 3010;
const int inf = 0xcfcfcfcf;

int n, m;

std::vector<std::vector<std::pair<int, int>>> g(N);
std::vector<std::vector<int>> f(N, std::vector<int>(N, inf));
int sz[N], money[N];

void dfs(int u) {
	if(money[u]) {
		f[u][1] = money[u];
		sz[u] = 1;
		return;
	}

	for(auto edge: g[u]) {
		int v = edge.first, w = edge.second;
		dfs(v);
		sz[u] += sz[v];
		for(int j = m; j >= 1; j -- ) {
			for(int k = 0; k <= std::min(j, sz[v]); k ++ ) {
				f[u][j] = std::max(f[u][j], f[u][j - k] + f[v][k] - w);
			}
		}
	}
}

int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	
	std::cin >> n >> m;

	for(int i = 1; i <= n - m; i ++ ) {
		int k;
		std::cin >> k;
		for(int j = 0; j < k; j ++ ) {
			int a, c;
			std::cin >> a >> c;
			g[i].push_back({a, c});
		}
	}

	for(int i = n - m + 1; i <= n; i ++ ) {
		std::cin >> money[i];
	}

	for(int i = 1; i <= n; i ++ ) f[i][0] = 0;

	dfs(1);
	int ans = 0;
	for(int i = m; i >= 1; i -- ) {
		if(f[1][i] >= 0) {
			ans = i;
			break;
		}
	}
	
	std::cout << ans;

	return 0;
}

到了这里,关于【LuoGU 1273】有线电视网——树上分组背包问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [动态规划] 分组背包

     开局思路            1.对dp[N] 的涵义进行定义         2.递推公式         3.初始化(此题不用)         4.遍历 1.dp[i][j]的定义:从1 - n组的物品里 选出总体积不超过j的 总价值。 2地推公式:dp[i][j] = max(dp[i][j], dp[i-1][j - v[i][k]] + w[i][k]);                  如若装入

    2024年02月21日
    浏览(34)
  • 分组背包问题

     题目来源 :9. 分组背包问题 - AcWing题库  题目 : 有 N 组物品和一个容量是 V 的背包。 每组物品有若干个,同一组内的物品 最多只能选一个 。 每件物品的体积是 vij,价值是 wij,其中 i 是组号,j 是组内编号。 求解将哪些物品装入背包,可使物品总体积不超过背包容

    2024年01月22日
    浏览(44)
  • HJ16 购物单 - 分组背包问题求解

    题目链接参考 HJ16 购物单_牛客题霸_牛客网 这道题需要通过动态规划来求解,首先先通过 ChatGPT 了解下如何 利用动态规划求解01背包问题和完全背包问题 ,以下是 ChatGPT 的答案 动态规划是什么? 动态规划(Dynamic Programming,DP)是一种常用的算法思想,用于解决多阶段决策问

    2023年04月21日
    浏览(40)
  • Spring Data Commons远程命令执行漏洞复现(CVE-2018-1273)

    一、漏洞说明 Spring Data是一个用于简化数据库访问,并支持云服务的开源框架,包含Commons、Gemfire、JPA、JDBC、MongoDB等模块。此漏洞产生于Spring Data Commons组件,该组件为提供共享的基础框架,适合各个子项目使用,支持跨数据库持久化。 Spring Data Commons组件中存在远程代码执行

    2024年02月09日
    浏览(52)
  • 如何下载央视网视频,下载视频播放花屏怎么办

    相信有很多人在下载央视网或者央视影音的视频遇到了虽然能下载但是花屏的情况,like this 或许你能找到hls-url,可能也用了猫爪或者video download等工具,但是下载下来的ts或者m3u8文件都是花屏的情况。下图是Opera GX浏览器检查元素界面,在网络-全部-预览当中可以看到类型为

    2024年02月11日
    浏览(47)
  • VGAN实现视网膜图像血管分割(基于pytorch)

    VGAN(Retinal Vessel Segmentation in Fundoscopic Images with Generative Adversarial Networks)出自2018年的一篇论文,尝试使用生成性对抗网络实现视网膜血管分割的任务,原论文地址:https://arxiv.org/abs/1706.09318 在github上有相应的源码仓库,不过由于版本的原因也会出现一些bug,本篇博客在复现项

    2024年01月16日
    浏览(42)
  • Luogu P3007 奶牛议会

    本题解使用 CC BY-NC-SA 4.0 许可 。 同步发布于 Luogu 题解区。 更好的观看体验 请点这里 。 笔者的博客主页 Luogu P3007 【USACO11JAN】 The Continental Cowngress G 前置知识: 2-SAT 、 Tarjan 。 (应该没有人会 2-sat 不会 tarjan 吧) 这道题除去输出 \\\'?\\\' 的部分是一道 2-SAT 的纯版子题。 其他题解

    2024年04月12日
    浏览(31)
  • Luogu P3294 背单词

    本题解使用 CC BY-NC-SA 4.0 许可 。 同步发布于Luogu题解区。 更好的观看体验 请点这里 。 笔者的博客主页 Luogu P3294 【SCOI2016】背单词 笔者在刷题的时候看到了这道好题。 花了四十分钟切掉以后,看了一下题解。 发现自己的想法不太一样。 所以想做一篇适合我这样的蒟蒻看的

    2024年04月08日
    浏览(45)
  • 11.动态规划:树形DP问题、树上最大独立集、树上最小支配集、换根DP、树上倍增(LCA)【灵神基础精讲】

    回溯和树形DP的区别(什么时候需要return结果?):对于回溯,通常是在「递」的过程中增量地构建答案,并在失败时能够回退,例如八皇后。对于递归,是把原问题分解为若干个相似的子问题,通常会在「归」的过程中有一些计算。如果一个递归能考虑用记忆化来优化,就

    2024年02月04日
    浏览(42)
  • 【luogu题解】T378828 位运算

    题目由 daiyulong20120222 创作(me) 并由 QBW1117完善以及数据 。 给定两个数 (x,y) ,在给定一个位运算符号 (c) 。 请你列出 (x,y) 进行 (c) 位运算是的算数竖式式。 注: 竖式这么列: 显示出两个数的完整二进制,包括前导零。 32个 \\\'-\\\'。 显示出 (ans) ,包括前导零。 位运算

    2024年02月05日
    浏览(54)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包