[SinGuLaRiTy] 树形DP专项测试

时间:2022-09-23 10:39:38

【SinGuLaRiTy-1015】 Copyright (c) SinGuLaRiTy 2017. All Rights Reserved.

对于所有的题目:Time Limit:1s  |  Memory:256 MB

第一题:最长链(HDU 2196 Computer)

题目描述

给定一棵有n个节点的树,求每个节点到其他节点的最大距离。

输入

输入第一行是一个自然数n(n≤10000);

接下来 (n−1) 行描述:第i行包含两个自然数 , 表示编号为i的节点连接到的节点编号和这条网线的长度..距离总长不会超过10^9. 每行中的两个数字用空格隔开。

输出

输出包含n行. 第i行表示对于离编号为i的节点最远的节点与该节点的距离Si(1≤i≤n)。

样例数据

样例输入 样例输出

3

1 1

1 2

2

3

3

数据规模

30% n≤100

100% n≤10000

题目分析

这道题是考试前一天课上讲的题目,如果我没记错的话应该是HDU 2196的原题。让我兴奋的是,尽管这道题没有被布置进作业当中,但我昨天就已经在HDU上AC了这道题,再打一遍代码也是相当的轻松,一种优越感油然而生......

下面,让我们来看看这道题的思路:对于任何一个节点M,我们可以将距离它最远的点的位置分为两类:①在以M为根节点的子树中,我们假设此种情况下的最远距离为maxdis_down;②在以M为根节点的子树之外,我们假设此种情况下的最远距离为maxdis_up。显而易见的是,此时这个点的最远距离ans[M]就为max(maxdis_down,maxdis_up)。我们重点看看第二种情况:maxdis_up=M到其父亲节点L的距离dis(M,L)+ans[L]。对此,我们可以定义一个dp[MAXN][3]的数组:

f[i][0]表示顶点为i的子树中,距离顶点i的最长距离(对应第一种情况);

f[i][1]表示i到其父亲节点的距离+其父亲的最长距离(对应第二种情况);

f[i][0]实际上不需要DP,dfs就可求解(本次dfs也求出次长距离);对于f[i][1],我们采取从父节点到子节点的策略。

假设有一L节点,它有n个子节点,我们用Vi来表示。

此时,我们又要分情况来讨论了:

①若Vi不是L的最长路径所经过节点,有f[Vi][1]=dis(Vi,L)+max(f[L][0],f[L][1]);

②若Vi是L的最长路径所经过节点,Vi的最长路径就不能再次被计算,我们就要“退而求其次”,使用第二长的路径Sec_dis,此时有f[Vi][1]=dis(Vi,L)+max(Sec_dis,f[L][1])。

<通过求树的直径解决>

树的直径是什么?就是在一棵树上存在的两点之间的最长距离所经过的路径。例如:

[SinGuLaRiTy] 树形DP专项测试

在该图中,树的直径,即距离最长的两点间路径为:7、5、2、1、3、6

在这里我们将用到一个结论:对于任意一个树中的节点来说,距离它最远的点一定是这棵树的直径的两个端点中的一个。【详细证明

通过这个结论,我们就可以先对两点进行dfs求最远点,确定树的直径的两个端点,然后对树中的点进行dfs求出长度即可。

STD Code

#include<cstring>
#include<cstdio>
#include<algorithm> #define MAXN 10010 using namespace std; struct node_a
{
int head;
}V[MAXN]; struct node_b
{
int v;
int w;
int next;
}E[MAXN]; int top; void init()
{
memset(V,-,sizeof(V));
top=;
}
void add_edge(int u,int v,int w)
{
E[top].v=v;
E[top].w=w;
E[top].next=V[u].head;
V[u].head=top++;
}
int dp[MAXN][];
void dfs1(int u)
{
int biggest=,bigger=;
for(int i=V[u].head;~i;i=E[i].next)
{
int v=E[i].v;
dfs1(v);
int tmp=dp[v][]+E[i].w;
if(biggest<=tmp)
{
bigger=biggest;
biggest=tmp;
}
else if(bigger<tmp)
{
bigger=tmp;
}
}
dp[u][]=biggest;
dp[u][]=bigger;
}
void dfs2(int u)
{
for(int i=V[u].head;~i;i=E[i].next)
{
int v=E[i].v;
dp[v][]=max(dp[u][],dp[v][]+E[i].w==dp[u][] ? dp[u][] : dp[u][])+E[i].w;
dfs2(v);
}
}
int main()
{int n;
scanf("%d",&n);
init();
for(int v=;v<=n;v++)
{
int u,w;
scanf("%d%d",&u,&w);
add_edge(u,v,w);
}
dfs1();
dp[][]=;
dfs2();
for(int i=;i<=n;i++)
{
printf("%d\n",max(dp[i][],dp[i][]));
}
return ;
}

第二题:电视转播

题目描述

一个电视网络计划转播一场重要的足球比赛。网络中的传输点和接收点(即用户)可以表示一棵树。这棵树的根是一个传输点,它将转播比赛。树的叶节点是可能要接受这场比赛的用户(他当然可以选择不看比赛,这样就不要交款)。其他非根节点,非叶节点的中间节点为数据的中转站。将一个信号从一个传输点传到另一个传输点的花费是给定的。整个转播的费用就是每一个传输费用的总和。每一个用户(叶节点)都准备付一定的钱来看这场比赛。电视网络公司要决定是否要给这个用户提供电视信号。例如:给一个节点传输信息的花费太大,而他愿意的付款也很少时,网络公司可能选择不给他转播比赛。写一个程序,找到一个传输方案使最多的用户能看到转播比赛,且转播的费用不超过所有接收信号用户的交款。

输入

输入文件的第一行包含两个整数N和M(2<=N<=3000,1<=M<=N-1)。N,M表示分别表示树的节点数和想观看比赛的用户数。树的根节点用1表示,中间节点的标号为2~N-M,用户的节点标号为N-M+1~N。接下来的N-M行表示传输点的信息(依次是节点1,2……): K A1 C1 A2 C2 …… Ak Ck 表示一个传输点将信号传给K个用户,每一个包含两个数A和C,A表示传输点或用户的节点号,C表示传输的花费。最后一行含有用户的数据,有M个整数表示他们看这场比赛愿意的付费。

输出

仅一行包含一个整数,最大的用户数。

样例数据

样例输入 样例输出

5 3

2 2 2 5 3

2 3 2 4 3

3 4 2

2

5 3

2 2 2 5 3

2 3 2 4 3

4 4 2

3

9 6

3 2 2 3 2 9 3

2 4 2 5 2

3 6 2 7 2 8 2

4 3 3 3 1 1

5

题目分析

注意到了题目结尾处“找到一个传输方案使最多的用户能看到转播比赛,且转播的费用不超过所有接收信号用户的交款”,这种熟悉的感觉——一定是01背包问题,一定是这样的!用户就相当于是物品,传输费用相当于是代价,总交款就是背包的容量......于是,题目类型确定:DP+01背包问题。

定义一个f[MAXN][MAXN]数组,f[l][m]表示:在根节点为l的子树中,将m个用户接入客户端所能得到的最大报酬。DP方程应该是比较好理解的,树形DP套上一个01背包的思路就行了:f[u][j+k]=max(f[u][j+k],f[u][j]+f[v][k]-edge[i].w)

STD Code

#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<algorithm> #define MAXN 3010
#define INF 0x3f3f3f3f using namespace std; struct node
{
int v;
int va;
}; vector <node> tu[MAXN];
int mo[MAXN],f[MAXN][MAXN],get[MAXN];
int n,m; void add(int u,int v,int va)
{
node p;
p.v=v;
p.va=va;
tu[u].push_back(p);
}
void init()
{
int tmp_1,tmp_2,tmp_3;
scanf("%d%d",&n,&m);
for(int i=;i<=n-m;i++)
{
scanf("%d",&tmp_1);
for(int j=;j<=tmp_1;j++)
{
scanf("%d%d",&tmp_2,&tmp_3);
add(i,tmp_2,tmp_3);
}
}
for(int i=n-m+;i<=n;i++)
{
scanf("%d",&mo[i]);
}
}
int dp(int x)
{
if(x>n-m)
{
f[x][]=mo[x];
get[x]=;
return get[x];
}
for(unsigned int i=;i<tu[x].size();i++)
{
get[x]+=dp(tu[x][i].v);
}
for(unsigned int i=;i<tu[x].size();i++)
{
for(int j=get[x];j>=;j--)
{
for(int k=min(j,get[tu[x][i].v]);k>=;k--)
{
f[x][j]=max(f[x][j],f[tu[x][i].v][k]+f[x][j-k]-tu[x][i].va);
}
}
}
return get[x];
}
int main()
{
init();
for(int i=;i<=n;i++)
for(int j=;j<=m;j++)
{
f[i][j]=-INF;
}
dp();
int ans=;
for(int i=;i<=m;i++)
{
if(f[][i]>=)
{
ans=max(ans,i);
}
}
printf("%d",ans);
return ;
}

第三题:叶子的颜色(CQOI 2009)

题目描述

给一棵m个结点的无根树,你可以选择一个度数大于1的结点作为根,然后给一些结点(根、内部结点和叶子均可)着以黑色或白色。你的着色方案应该保证根结点到每个叶子的简单路径上都至少包含一个有色结点(哪怕是这个叶子本身)。

对于每个叶结点u,定义c[u]为从根结点到u的简单路径上最后一个有色结点的颜色。给出每个c[u]的值,设计着色方案,使得着色结点的个数尽量少。

输入

第一行包含两个正整数m, n,其中n是叶子的个数,m是结点总数。结点编号为1,2,…,m,其中编号1,2,… ,n是叶子。以下n行每行一个0或1的整数(0表示黑色,1表示白色),依次为c[1],c[2],…,c[n]。以下m-1行每行两个整数a,b(1<=a < b <= m),表示结点a和b 有边相连。

输出

仅一个数,即着色结点数的最小值。

样例数据

样例输入 样例输出

5 3

0

1

0

1 4

2 5

4 5

3 5

2

题目分析

在本题当中,题目并没有给出树的根节点,于是首先想到:第一步一定是找根......好吧,这个思路是错的,在最后我们会发现:无论选择哪一个节点作为根,都不会影响答案以及染色状态。比如,当前选择一个节点x为根有最优解,y为它某一个的儿子节点,x和y不会同色——同色必然不为最优解,如果不同色,y转化为x的儿子,这样必然不会影响最优解。

由于发现在一个子树中,不可能存在两个颜色不同的点未满足条件,我们可以进行如下定义:
f[u][0]表示以u为根节点的子树中不存在未满足条件的最小染色节点数;

f[u][1]表示以u为根节点的子树中存在被染色为0的节点不满足条件时的最小染色节点数;

f[u][2]表示以u为根节点的子树中存在被染色为1的节点不满足条件时的最小染色节点数;

对此:tmp_1=∑(f[v][1]);   tmp_2=∑(min(f[v][0],f[v][1]));   tmp_3=∑(min(f[v][0],f[v][2]));

由此可得:f[u][0]=min(tmp_1,tmp_2+1,tmp_3+1);   f[u][1]=min(tmp_2,tmp_3+1);   f[u][2]=min(tmp_2+1,tmp_3);

STD Code

#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<vector> #define MAXN 10010
#define INF 0x3f3f3f3f using namespace std; vector <int> vec[MAXN]; int n,m;
int color,f[MAXN][];
bool vis[MAXN]; void dp(int u)
{
vis[u]=;
int tmp_1=,tmp_2=,tmp_3=;
bool flag=;
for(unsigned int i=;i<vec[u].size();i++)
{
int v=vec[u][i];
if(vis[v])
continue;
dp(v);
tmp_1+=f[v][];
tmp_2+=min(f[v][],f[v][]);
tmp_3+=min(f[v][],f[v][]);
flag=;
}
if(flag)
{
f[u][]=min(tmp_1,min(tmp_2+,tmp_3+));
f[u][]=min(tmp_2,tmp_3+);
f[u][]=min(tmp_2+,tmp_3);
}
}
int main()
{
int u,v;
scanf("%d%d",&n,&m);
memset(f,INF,sizeof(f));
for(int i=;i<=m;i++)
{
scanf("%d",&color);
f[i][]=;
f[i][color+]=;
}
for(int i=;i<=n-;i++)
{
scanf("%d%d",&u,&v);
vec[u].push_back(v);
vec[v].push_back(u);
}
dp(n);
printf("%d\n",f[n][]);
return ;
}

Time : 2017-04-04

[SinGuLaRiTy] 树形DP专项测试的更多相关文章

  1. HDU 1561 树形DP入门

    The more, The Better Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Oth ...

  2. hdu 1561 The more&comma; The Better&lpar;树形dp&comma;基础&rpar;

    The more, The Better Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Oth ...

  3. HDU 5834 &lbrack;树形dp&rsqb;

    /* 题意:n个点组成的树,点和边都有权值,当第一次访问某个点的时候获得利益为点的权值 每次经过一条边,丢失利益为边的权值.问从第i个点出发,获得的利益最大是多少. 输入: 测试样例组数T n n个数 ...

  4. 动态规划——树形dp

    动态规划作为一种求解最优方案的思想,和递归.二分.贪心等基础的思想一样,其实都融入到了很多数论.图论.数据结构等具体的算法当中,那么这篇文章,我们就讨论将图论中的树结构和动态规划的结合——树形dp. ...

  5. app专项测试自动化测试方法思路与实现

    秉着个人意愿打算把python+rf接口自动进行彻底结束再做些其它方面的输出~但事与愿违,但领导目前注重先把专项测试方面完成,借此,先暂停python+rf(主要是与Jenkins集成+导入DB+微信 ...

  6. 树形动态规划(树形DP)入门问题—初探 &amp&semi; 训练

    树形DP入门 poj 2342 Anniversary party   先来个题入门一下~ 题意: 某公司要举办一次晚会,但是为了使得晚会的气氛更加活跃,每个参加晚会的人都不希望在晚会中见到他的直接上 ...

  7. HDU 1561 The more&comma; The Better 经典树形DP

    The more, The Better Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Oth ...

  8. 【bzoj1369】&lbrack;Baltic2003&rsqb;Gem 树形dp

    题目描述 给出一棵树,要求你为树上的结点标上权值,权值可以是任意的正整数 唯一的限制条件是相临的两个结点不能标上相同的权值,要求一种方案,使得整棵树的总价值最小. 输入 先给出一个数字N,代表树上有N ...

  9. HDU 1561 The more&comma; The Better【树形DP&sol;有依赖的分组背包】

    ACboy很喜欢玩一种战略游戏,在一个地图上,有N座城堡,每座城堡都有一定的宝物,在每次游戏中ACboy允许攻克M个城堡并获得里面的宝物.但由于地理位置原因,有些城堡不能直接攻克,要攻克这些城堡必须先 ...

随机推荐

  1. c&num;下volatile关键字

      volatile多用于多线程的环境,当一个变量定义为volatile时,读取这个变量的值时候每次都是从momery里面读取而不是从cache读.这样做是为了保证读取该变量的信息都是最新的,而无论其 ...

  2. Java用来进行批量文件重命名,批量提取特定类型文件

    原因: 因为在网上下载视频教程,有的名字特别长,一般都是机构或者网站的宣传,不方便直接看到视频的简介,所以做了下面的第一个功能. 因为老师发的课件中,文件夹太多,想把docx都放在同一个文件夹下面,一 ...

  3. IIS服务的部署

    1.安装 C:\Windows\Microsoft.NET\Framework\v4.0.30319 aspnet_regiis -i2.添加应用程序,选择Asp.net4.03.应用目录 IIS_U ...

  4. JavaSE——面向对象与面向过程、类与对象、&lpar;属性、方法、构造器&rpar;等

    一:面向对象与面向过程 二者都是一种思想,面向对象是相对于面向过程而言的. 面向过程: 1.面向过程思想强调的是过程(动作). 2.在面向过程的开发中,其实就是面向着具体的每一个步骤和过程,把每一个步 ...

  5. CentOS系统中手动调整系统时间的方法

    我们一般使用“date -s”命令来修改系统时间.比如将系统时间设定成1996年6月10日的命令如下. #date -s 06/10/96 将系统时间设定成下午1点12分0秒的命令如下. #date ...

  6. 使用Teleport Pro离线下载网页所有内容

    在学习生活中,碰到网页中内容太多,如何讲其保存到本地,已方便随时查看呢? 使用Teleport Pro就可以解决问题:     首先下载Teleport Pro V1.54 汉化绿色版的,解压完之后 ...

  7. spring schema自定义

    今天看了一下分布式服务框架的那本书,于是里面提到了spring schema的自定义,于是去简单的了解了一下 参考资源:spring schema扩展: http://www.yihaomen.com ...

  8. Sql Server尝试读取或写入受保护的内存。这通常指示其他内存已损坏

    今日遇到这样一个问题,用vs2010调试C#代码时,只要代码一运行到跟数据库关联的地方时,编译器就报错误,给的提示如:调试器已附加,要继续需要分离什么的,咋一看还以为是vs中调试器设置的问题,可后来仔 ...

  9. leetcode — word-break

    import java.util.Arrays; import java.util.HashSet; import java.util.Set; /** * Source : https://oj.l ...

  10. Codeforces Round &num;374 &lpar;Div&period; 2&rpar; B&period; Passwords 贪心

    B. Passwords 题目连接: http://codeforces.com/contest/721/problem/B Description Vanya is managed to enter ...