『战略游戏 最大利润 树形DP』
<更新提示>
<第一次更新> 通过两道简单的例题,我们来重新认识树形DP。
<正文>
战略游戏(luoguP1026)
Description
Bob喜欢玩电脑游戏,特别是战略游戏。但是他经常无法找到快速玩过游戏的办法。现在他有个问题。他要建立一个古城堡,城堡中的路形成一棵树。他要在这棵树的结点上放置最少数目的士兵,使得这些士兵能了望到所有的路。注意,某个士兵在一个结点上时,与该结点相连的所有边将都可以被了望到。
请你编一程序,给定一树,帮Bob计算出他需要放置最少的士兵。
Input Format
输入文件中数据表示一棵树,描述如下: 第一行 N,表示树中结点的数目。 第二行至第N+1行,每行描述每个结点信息,依次为:该结点标号i,k(后面有k条边与结点I相连),接下来k个数,分别是每条边的另一个结点标号r1,r2,...,rk。 对于一个n(0<n<=1500)个结点的树,结点标号在0到n-1之间,在输入文件中每条边只出现一次。
Output Format
输出文件仅包含一个数,为所求的最少的士兵数目。
Sample Input
4
0 1 1
1 2 2 3
2 0
3 0
Sample Output
1
解析
在树形图求解最优化问题,很明显就是一道树形DP的模板题。
我们根据树形\(DP\)通常设置状态的套路来设计这道题的状态:\(f[i][0/1]\)代表以\(i\)为根的子树中的最小士兵数,\(1\)代表节点i放了士兵,\(0\)代表节点i没放士兵。
对于状态的转移,我们可以分两种情况讨论:
1.节点\(i\)放一个士兵,节点\(i\)的子节点可以放士兵,也可以不放士兵
2.节点\(i\)不放士兵,节点i的各个子节点都必须放士兵
那么所对应的状态转移方程就是:
\\2.f[i][0]=\sum_{j \in son(i)}f[j][1]
\]
注意到题中没有明确的树根的指明,所以我们只要随便找一个入度为0的点当做树根执行记忆化搜索即可。
\(Code:\)
#include<bits/stdc++.h>
using namespace std;
const int N=1500+30;
int n,f[N][2],ans=0x3f3f3f3f,vis[N];vector < int >Link[N];
inline void input(void)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
int index,num,temp;
scanf("%d%d",&index,&num);
for(int j=1;j<=num;j++)
{
scanf("%d",&temp);
Link[index].push_back(temp);
vis[temp]=1;
}
}
}
inline void dp(int root)
{
f[root][1]=1;
f[root][0]=0;
for(int i=0;i<Link[root].size();i++)
{
int Son=Link[root][i];
dp(Son);
f[root][0]+=f[Son][1];
f[root][1]+=min(f[Son][0],f[Son][1]);
}
return;
}
int main(void)
{
freopen("strategi.in","r",stdin);
freopen("strategi.out","w",stdout);
input();
int root;
for(int i=0;i<n;i++)
{
if(!vis[i])
{
root=i;
break;
}
}
dp(root);
printf("%d\n",min(f[root][0],f[root][1]));
}
最大利润(SMOJ1782)
Description
政府邀请了你在火车站开饭店,但不允许同时在两个相连接的火车站开。
任意两个火车站有且只有一条路径,每个火车站最多有50个和它相连接的火车站。
告诉你每个火车站的利润,问你可以获得的最大利润为多少。
Input Format
第一行输入整数N(<=100000),表示有N个火车站,分别用1,2,...,N来编号。
接下来N行,每行一个整数表示每个站点的利润,接下来N-1行描述火车站网络,每行两个整数,表示相连接的两个站点。
Output Format
输出一个整数表示可以获得的最大利润
Sample Input
6
10
20
25
40
30
30
4 5
1 3
3 4
2 3
6 4
Sample Output
90
解析
这道题和上一道题很像,都是很明显的树形\(DP\)。但是两道题有不同之处:上一题是覆盖相邻的边,但这题是覆盖相邻的点。上一题是必须全部覆盖,这一题是可以不全部覆盖,但不能重叠。我们仍然可以设\(f[i][0/1]\)代表以\(i\)为根的子树中的最大利润,\(0\)代表节点i没有开餐馆,\(1\)代表节点\(i\)开了餐馆。
状态的转移就和上一题很相似了:
1.若节点\(i\)开了餐馆,则它的子节点可以开餐馆,也可以不开
2.若节点\(i\)没开餐馆,则它的子节点都不能开餐馆
状态转移方程:
\\f[i][0]=\sum_{j \in son(i)}f[j][0]+a[i]
\]
注意在记忆化搜索的时候需要开一个访问数组标记,避免递归死循环。
\(Code:\)
#include<bits/stdc++.h>
using namespace std;
const int N=100000+80;
int n,f[N][2],a[N],vis[N],ans=0;
vector < int > Link[N];
inline void input(void)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
Link[u].push_back(v);
Link[v].push_back(u);
}
}
inline void dp(int root)
{
f[root][0]=0;
f[root][1]=a[root];
for(int i=0;i<Link[root].size();i++)
{
int Son=Link[root][i];
if(vis[Son])continue;
vis[Son]=1;
dp(Son);
f[root][0]+=max(f[Son][1],f[Son][0]);
f[root][1]+=f[Son][0];
}
return;
}
int main(void)
{
freopen("profit.in","r",stdin);
freopen("profit.out","w",stdout);
input();
memset(f,0x00,sizeof f);
memset(vis,0x00,sizeof vis);
vis[1]=1;
dp(1);
printf("%d\n",max(f[1][1],f[1][0]));
}
<后记>
『战略游戏 最大利润 树形DP』的更多相关文章
- 『没有上司的舞会 树形DP』
树形DP入门 有些时候,我们需要在树形结构上进行动态规划来求解最优解. 例如,给定一颗\(N\)个节点的树(通常是无根树,即有\(N-1\)条无向边),我们可以选择任意节点作为根节点从而定义出每一颗子 ...
- 『土地征用 Land Acquisition 斜率优化DP』
斜率优化DP的综合运用,对斜率优化的新理解. 详细介绍见『玩具装箱TOY 斜率优化DP』 土地征用 Land Acquisition(USACO08MAR) Description Farmer Jo ...
- 『大 树形dp』
大 Description 滑稽树上滑稽果,滑稽树下你和我,滑稽树前做游戏,滑稽多又多.树上有 n 个节点,它们构成了一棵树,每个节点都有一个滑稽值. 一个大的连通块是指其中最大滑稽值和最小滑稽值之差 ...
- 『You Are Given a Tree 整体分治 树形dp』
You Are Given a Tree Description A tree is an undirected graph with exactly one simple path between ...
- 『快乐链覆盖 树形dp』
快乐链覆盖 Description 给定一棵 n 个点的树,你需要找至多 k 条互不相交的路径,使得它们的长度之和最大 定义两条路径是相交的:当且仅当存在至少一个点,使得这个点在两条路径中都出现 定义 ...
- 『kamp 树形dp』
kamp Description jz 市的云台山是个很美丽的景区,小 x 暑期到云台山打工,他的任务是开景区的大巴. 云台山景区有 N 个景点,这 N 个景点由 N-1 条道路连接而成,我们保证这 ...
- 『树上匹配 树形dp』
树上匹配 Description 懒惰的温温今天上班也在偷懒.盯着窗外发呆的温温发现,透过窗户正巧能看到一棵 n 个节点的树.一棵 n 个节点的树包含 n-1 条边,且 n 个节点是联通的.树上两点之 ...
- 『最短Hamilton路径 状态压缩DP』
状压DP入门 最短Hamilton路径 Description 给定一张 n(n≤20) 个点的带权无向图,点从 0~n-1 标号,求起点 0 到终点 n-1 的最短Hamilton路径. Hamil ...
- 『玩具装箱TOY 斜率优化DP』
玩具装箱TOY(HNOI2008) Description P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京.他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊 ...
随机推荐
- Android进阶:一、日志打印和保存策略
前言: 项目开始没有做好日志统计工作,每次有问题后端都得找前端对接,严重影响工作效率.最近特地在项目中加上日志保存策略,在此分享,供需要的人学习. 一.更详细的日志信息 既然决定自定义一个log,那我 ...
- ScriptEngine执行复杂js报数组越界
import javax.script.Invocable; import javax.script.ScriptEngine; import javax.script.ScriptEngineMan ...
- Hadoop优化
一.影响MR程序效率的因素 1.计算机性能: CPU.内存.磁盘.网络, 计算机的性能会影响MR程序的速度与效率 2.I/O方面 1)数据倾斜(代码优化) 2)map和reduce数量设置不合理(通过 ...
- Java 扫描实现 Ioc 动态注入,过滤器根据访问url调用自定义注解标记的类及其方法
扫描实现 Ioc 动态注入 参考: http://www.private-blog.com/2017/11/16/java-%e6%89%ab%e6%8f%8f%e5%ae%9e%e7%8e%b0-i ...
- oracle行转列、列转行、连续日期数字实现方式及mybatis下实现方式
转载请注明出处:https://www.cnblogs.com/funnyzpc/p/9977591.html 九月份复习,十月份考试,十月底一直没法收心,赶在十一初 由于不可抗拒的原因又不得不重新找 ...
- 如何让pandas表格直接转换为markdown表格
https://stackoverflow.com/questions/33181846/programmatically-convert-pandas-dataframe-to-markdown-t ...
- python爬取网页内容demo
#html文本提取 from bs4 import BeautifulSoup html_sample = '\ <html> \ <body> \ <h1 id = & ...
- VB用API模拟截屏键PrintScreen
很多人用 SendKeys "{PRTSC}" 模拟截屏键 PrintScreen 的时候提示<错误:'70' 拒绝的权限>,于是经常遇到人问...干脆写下来 '声明 ...
- 编程菜鸟的日记-Linux无处不在
原文来自:http://www.linuxfederation.com/linux-everywhere Linux无处不在 “Linux无处不在.从空间站到微波炉到有Linux.”你可能听说很多以及 ...
- synchronized关键字的详细分析和代码实例
在Java中,一般都是通过同步机制来解决线程安全问题的,在JDK 5.0之后又新增了Lock的方式来实现线程安全.所以说实现线程安全方式一共有三种方法 方式一: synchronized(同步监视器) ...