LuoguP1273 有线电视网 树形DP

本文介绍了一道关于有线电视网转播比赛的问题,采用动态规划算法求解最大用户数的同时确保不亏本。文章详细阐述了解题思路、状态定义及转移方程,并附上了实现代码。

首先,我很机动,这还是蒟蒻第一次自主写出一道DP题目,没有看题解,虽然用了点数据来调试,但是毕竟是第一次,以后绝对会越来越好的.
传送门呐~

题目描述

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

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

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

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

输入格式

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

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

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

K A 1 C 1 A 2 C 2 … A k C k K A_1C_1 A_2 C_2 … A_k C_k KA1C1A2C2AkCk

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

输出格式

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

输入输出样例
输入 #1

5 3

2 2 2 5 3

2 3 2 4 3

3 4 2

输出 #1

2

思路与解析
第一眼看到这题我也是完全没有思路,脑阔里全四怎样暴力,然后我把自己的博客看了一遍(不用怀疑,我就是来安利的)顺着思路走,就有了以下的思考过程(大佬可跳过):

首先,理清楚这道题所要求的答案:在不亏钱的情况下最大的用户数,一般来说我们需要根据这个东西来设状态, d p [ x ] [ i ] dp[x][i] dp[x][i],第一维 x x x表示当前节点 x x x应该没问题叭,那么第二维呢?

我思考了一会,有两种可能: 1. d p [ x ] [ 0 / 1 ] 1.dp[x][0/1] 1.dp[x][0/1],表示该节点选或不选 2. d p [ x ] [ i ] 2.dp[x][i] 2.dp[x][i],表示该节点中用 i i i的费用.

现在就来分别思考状态转移.

你会发现,如果按照第一种来定义状态,那么如果一个非叶子节点中有2个叶子节点也就是用户,那么这种定义方法只有两种选择:两个都选或两个都不选.但是实际上有很多种选择:只选第一个;只选第二个;两个都选;两个都不选.这样就会少考虑很多种情况,那么最终得到的答案就不会是最优的.

而第二种方法的思想来源是01背包,因为你看每个用户是不是都有一个花费,和一个价值,只不过当两个叶子节点的LCA不是根节点时,花费就会重合,所以不能直接01背包,但我们是不是可以借用01背包的状态(其实就是自己想不出),那么再来考虑状态转移,然后我就发现边界是什么想不出了,因为总容量(也就是能用的钱数)不是固定的,而花费也不是固定的,就不好转移.

于是我冥思苦想,绞尽脑汁,发挥我的聪明才智,就连蒙带猜想到了这个:

设状态为 d p [ x ] [ i ] dp[x][i] dp[x][i]表示在以 x x x为根的子树中选 i i i个叶子节点所赚的钱(可能为负数,也就表示亏了钱),状态转移方程如下:
d p [ x ] [ i ] = m a x ( d p [ x ] [ i ] , d p [ s o n [ x ] [ j ] ] [ k ] + d p [ x ] [ i − k ] ) dp[x][i]=max(dp[x][i], dp[son[x][j]][k]+dp[x][i-k]) dp[x][i]=max(dp[x][i],dp[son[x][j]][k]+dp[x][ik])
s o n [ x ] [ j ] son[x][j] son[x][j]为节点 x x x的第 j j j个儿子

没看懂的再仔细思考一下,我们对于 x x x的每一个儿子,在 x x x的这个儿子更新后我们就有了 d p [ s o n [ x ] [ j ] ] [ 1 ⋯ s i z e [ s o n [ x ] [ j ] ] ] dp[son[x][j]][1\cdots size[son[x][j]]] dp[son[x][j]][1size[son[x][j]]] s i z e [ x ] size[x] size[x]指以x为根节点的子树中叶子节点的个数,不是子树大小),那么我们就可以用该子节点来更新 x x x,这样,可以先不考虑是否亏钱,因为有可能在上面的某一个节点更新答案时,它的另一个子节点赚了很多钱可以补上当前节点所亏的钱,然而如果这时候你为了不亏钱,而少选了一个点,最终答案就有可能会少一个点,就会有后效性,也就是说,只要保证在匹配到 x x x时选 i i i个点所要赚的钱越多(或者亏的钱越少)就行了.

最后的答案也很简单, i i i s i z e [ 1 ] size[1] size[1]到0,第一个 d p [ 1 ] [ i ] ≥ 0 dp[1][i]\ge0 dp[1][i]0 i i i就是我们所要求的最大用户数.

发一下弱弱的我的丑丑的代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#define R register int 
using namespace std;
const int N=3e3+5, M=3e3+5;

int n, m, tot;
int s[N], a[N], dp[N][N];, 

//s[x]指以x为根节点的子树中叶子节点的个数
int h[N], w[M], to[M], nex[M];//链式前向星存图

void add(int k){
	int x, y;
	scanf ("%d%d", &x, &y);
	nex[++tot]=h[k];
	to[tot]=x;
	w[tot]=y;
	h[k]=tot;
}

void dfs(int rot){
	if (a[rot]){//叶子节点的处理
		dp[rot][1]=a[rot];
		s[rot]=1;
		return ;
	}for (R i=h[rot];i;i=nex[i]){
		dfs(to[i]);
		s[rot]+=s[to[i]];
	}for (R j=m;j>=1;--j) dp[rot][j]=-1e9;
	for (R i=h[rot];i;i=nex[i])//遍历每个儿子
		for (R j=s[rot];j>=1;--j)//边界有点ex,调了我老久
			for (R k=j-s[to[i]];k<=j;++k)
				dp[rot][j]=max(dp[rot][j], dp[rot][k]+dp[to[i]][j-k]-w[i]);
}

int main (){
	int k;
	scanf ("%d%d", &n, &m);
	for (R i=1;i<=n;++i)	dp[i][0]=0;
	//每个节点都不选,那就是不亏不赚
	for (R i=1;i<=n-m;++i){
		scanf ("%d", &k);
		for (R j=1;j<=k;++j) add(i);
	}for(R i=n-m+1;i<=n;++i) scanf ("%d", &a[i]);
	dfs(1);
	for(R i=s[1];i>=0;--i)
		if(dp[1][i]>=0){//只要dp[1][i]>=0,就不亏,满足题意
			printf("%d\n", i);
			return 0;
		}

	return 0;
}

嘿嘿嘿,你竟然有耐心看完惹,也算没辜负我写了这么久,谢谢呐~

内容概要:本文提出了一种基于非合作博弈理论的居民负荷分层调度模型,并结合双层鲸鱼优化算法(Two-level Whale Optimization Algorithm)进行高效求解,模型与算法均通过Matlab代码实现。研究针对电力系统中居民侧用电负荷的复杂调度问题,引入非合作博弈机制刻画各用户之间的利益竞争关系,实现负荷的分层优化分配;同时设计双层优化架构,上层优化资源配置,下层模拟用户自主决策行为,提升了模型的实用性与合理性。通过智能优化算法求解多层级、非凸非线性的博弈模型,有效提高了调度方案的收敛性与全局寻优能力,适用于现代智能电网中的需求侧管理与能源优化场景。; 适合人群:具备电力系统基础理论知识和Matlab编程能力,从事智能电网、能源优化调度、需求侧管理、博弈论应用等方向的科研人员、高校研究生及工程技术人员。; 使用场景及目标:①应用于居民区电力负荷的分层优化调度系统设计与仿真分析;②为非合作博弈在多主体能源系统建模中的应用提供方法论支持;③利用双层鲸鱼算法解决具有嵌套结构的复杂双层优化问题,提升求解效率与调度方案的可行性。; 阅读建议:建议读者结合提供的Matlab代码深入理解模型构建逻辑与算法实现流程,重点关注博弈模型的效用函数设计、纳什均衡求解思路以及双层优化结构的迭代机制,宜配合实际用电数据开展复现实验以验证模型有效性与鲁棒性。
内容概要:本文围绕基于自适应神经模糊推理系统(ANFIS)智能控制器的可再生能源微电网功率管理系统展开研究,结合Simulink仿真实现,深入探讨了微电网中功率的智能调控与经济机组组合调度问题。通过引入ANFIS控制器,有效应对风能、光伏等可再生能源出力的波动性与不确定性,提升系统运行的稳定性与电能质量。研究内容涵盖微电网多源协调控制策略、功率平衡管理、优化调度模型构建及仿真验证,实现了对分布式电源、储能系统和负荷的协同优化,兼顾经济性与可靠性目标,并通过仿真平台验证了所提方法的有效性与优越性。; 适合人群:具备电力系统、自动化或新能源相关专业背景,熟悉Matlab/Simulink仿真环境,从事微电网能量管理、智能控制、能源优化等领域研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①用于高比例可再生能源接入场景下的微电网能量管理系统研发与教学实践;②为实现微电网功率稳定控制与经济高效运行提供先进的智能控制解决方案;③支撑高水平学术论文复现、科研课题攻关及实际工程项目的仿真验证与方案优化。; 阅读建议:建议结合提供的Simulink模型与相关代码进行动手实践,重点关注ANFIS控制器的设计流程、规则库构建与参数调优方法,并通过与传统PID或MPC控制策略的对比实验,深入理解其在动态响应与鲁棒性方面的优势。同时可进一步拓展文中提出的优化调度逻辑,应用于多目标、多约束的复杂实际应用场景中。
内容概要:本文档聚焦于“直流电机双闭环控制Matlab仿真”,系统阐述了基于Matlab/Simulink平台实现直流电机双闭环控制系统(主要包括速度环与电流环)的设计与仿真全过程。通过构建直流电机的数学模型,结合PI控制器进行调控,实现对电机转速和电枢电流的高精度动态控制,验证控制策略的稳定性与响应性能。文档详细介绍了仿真模型的搭建流程、关键参数的整定方法、系统动态波形的分析手段以及仿真结果的有效性验证,体现了经典自动控制理论在实际电机系统中的工程应用,是电机控制与电力电子技术相结合的典型研究案例。; 适合人群:具备自动控制原理、电机与拖动基础、电力电子技术和Matlab/Simulink仿真能力的电气工程、自动化、机电一体化等专业的本科生、研究生及从事电机驱动系统研发的工程技术人员。; 使用场景及目标:①作为高校课程设计或实验教学材料,帮助学生深入理解双闭环调速系统的工作机理与工程实现;②服务于科研项目,为新型电机控制算法(如滑模、模糊PID等)的开发与性能对比提供基础仿真验证平台;③作为工业界产品前期设计的仿真工具,用于评估不同控制策略在动态响应、抗干扰能力和稳态精度方面的可行性。; 阅读建议:建议读者在学习过程中紧密结合自动控制理论知识,亲手在Simulink环境中搭建完整的双闭环仿真模型,通过反复调整PI控制器的比例与积分参数,观察并分析转速、电流的阶跃响应曲线,从而深刻理解反馈控制的本质、系统稳定性条件以及参数整定对动态性能的影响,进而掌握电机控制系统的设计精髓。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值