<更新提示>

<第一次更新>


<正文>

快乐链覆盖

Description

给定一棵 n 个点的树,你需要找至多 k 条互不相交的路径,使得它们的长度之和最大

定义两条路径是相交的:当且仅当存在至少一个点,使得这个点在两条路径中都出现

定义一条路径的长度为该路径经过的点的数量

这个题非常简单,非常传统,但为了让它变成一道能一个顶俩的题,出题人决定让你输出任意一组方案。

Input Format

第一行一个正整数 T 表示数据组数

接下来,对于每组数据:

第一行两个整数 n,kn,k

接下来 n−1 行,每行两个整数 a,b 描述一条树边

Output Format

对于每组数据,第一行输出一个整数表示最大的长度之和

之后你要输出任意一组长度之和最大的方案之后你要输出任意一组长度之和最大的方案,第一行一个整数 P 表示你的方案由几条路径构成,接下来 P 行每行两个整数描述一条路径

当然,如果你只能求出答案,不能求出任意一组方案的话,本题也会给你一些部分分,具体看数据范围中的描述

但是请注意:你必须保证你的输出的格式是正确的,首先你输出的 P 必须不超过 k 且是非负整数,且无论你的方案正不正确,后面都要描述 P 条路径,例如你输出 P=2 但是只输出了一条路径的话,后面的其他组的输出可能就会被读入作为第二条路径,这会导致你得不到该有的分数

Sample Input

1
5 2
1 2
1 3
1 4
1 5

Sample Output

4
2
5 5
4 3

解析

这显然是一道树形\(dp\),我们可以先不考虑输出方案。

我们可以先设置简单的状态\(f[x][k]\)代表以\(x\)为根的子树中选了\(k\)条链的最大长度之和,但是我们发现好像不太适合从子树转移。

我们可以考虑一下从子树上转移过来会有几种情况,一个就是根节点\(x\)不包含在任何一条链中,还有就是根节点\(x\)包含在某个链中。

如果\(x\)包含在某个链中,还有两种情况:\(1.\) \(x\)现在是某个链的一端,也就是说,这条链还可以继续向上拓展。 \(2.\) \(x\)是某条链中间的一个点,也就是说有两条链在点\(x\)处合并了。

那样就可以设置状态了,\(f[x][k][0/1/2]\)就分别代表了如上的三种情况。

于是我们可以考虑合并,最简单的方式就是先不考虑这棵子树影响了根节点\(x\),把所有状态先暴力合并了,然后再考虑这棵子树向上延展,或者与其他链合并这两种影响根节点\(x\)的情况,单独转移。

这种复杂的树形\(dp\)由于没有显式地划分阶段,所以建议用滚动数组的方式转移,不建议直接转移,那样容易出现\(dp\)顺序的问题。

然后我们再考虑输出方案。一般的\(dp\)输出方案的方式都是记录每一个状态是从哪些状态转移而来的,但是显然这种背包类的\(dp\)不适合,他可能是由很多子节点共同转移过来的,直接记录空间是不够的。

但是我们考虑到一个节点顶多也就是给了他父亲一个贡献,所以我们可以换一种记录方式,把转移记录在子节点上。

记录了方案之后,我们就可以再通过一遍\(dfs\)输出了。当然,我们仍然需要对转移进行讨论,以便找到链的两个端点。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int N = 10020 , K = 520 , INF = 0x3f3f3f3f;
inline int read(void)
{
int x = 0 , w = 0; char ch = ' ';
while ( !isdigit(ch) ) w |= ch == '-' , ch = getchar();
while ( isdigit(ch) ) x = x * 10 + ch - 48 , ch = getchar();
return w ? -x : x;
}
int n,k,f[N][K][3],dp[K][3],size[N];
vector < pair <int,int> > ans;
pair < int , int > fr[N][K][3];
vector < int > e[N];
inline void input(void)
{
n = read() , k = read();
for (int i=1;i<n;i++)
{
int x = read() , y = read();
e[x].push_back( y );
e[y].push_back( x );
}
}
inline bool upd(int &a,int b) { if ( b > a ) return a = b , true; return false; }
inline void merge(int x,int y)
{
memcpy( dp , f[x] , sizeof f[x] );
for (int i=0;i<=size[x];i++)
for (int j=0;j<=size[y]&&i+j<=k+1;j++)
{
if ( i + j <= k )
{
for (int a=0;a<3;a++)
for (int b=0;b<3;b++)
if ( upd( dp[i+j][a] , f[x][i][a] + f[y][j][b] ) )
fr[y][i+j][a] = make_pair( j , b );
if ( j > 0 )
if ( upd( dp[i+j][1] , f[x][i][0] + f[y][j][1] + 1 ) )
fr[y][i+j][1] = make_pair( j , -1 );
}
if ( i + j > 1 && j > 0 )
if ( upd( dp[i+j-1][2] , f[x][i][1] + f[y][j][1] ) )
fr[y][i+j-1][2] = make_pair( j , -1 );
}
size[x] += size[y];
memcpy( f[x] , dp , sizeof dp );
}
inline void dfs(int x,int fa)
{
for (int i=0;i<=k;i++)
for (int j=0;j<3;j++)
f[x][i][j] = -INF , fr[x][i][j] = make_pair(-INF,-INF);
size[x] = 1 , f[x][0][0] = 0;
f[x][1][1] = f[x][1][2] = 1;
for ( auto y : e[x] )
if ( y != fa )
dfs( y , x ) , merge( x , y );
}
inline int findpath(int x,int fa,int cnt,int op)
{
if ( !cnt ) return 0;
reverse( e[x].begin() , e[x].end() );
int _op,cur,c,t;
_op = op , cur = _op == 1 ? x : 0;
if ( op < 0 ) op = 1;
for ( int y : e[x] )
if ( y != fa )
{
if ( cnt == 0 ) break;
tie(c,t) = fr[y][cnt][op];
if ( t == -INF ) continue;
if ( t == -1 )
{
int ver = findpath( y , x , c , t );
if ( ver != 0 )
{
if ( cur )
ans.push_back( make_pair(cur,ver) ) , cur = 0;
else cur = ver;
}
cnt -= c - (--op);
}
else cnt -= c , findpath(y, x, c, t);
}
if ( _op > 0 && cur )
ans.push_back( make_pair(cur,cur) ) , cur = 0;
else if ( _op < 1 && !cur ) return x;
return cur;
}
inline void reset(void)
{
ans.clear();
for (int i=1;i<=n;i++)
e[i].clear();
}
int main(void)
{
int T; scanf("%d",&T);
ans.clear();
while ( T --> 0 )
{
input();
dfs( 1 , 0 );
int num = 0 , op = 0;
for (int i=1;i<=k;i++)
for (int j=0;j<3;j++)
if ( f[1][i][j] > f[1][num][op] )
num = i , op = j;
printf("%d\n",f[1][num][op]);
findpath( 1 , 0 , num , op );
printf("%d\n",ans.size());
for ( auto p : ans )
{
int x,y;
tie( x , y ) = p;
printf("%d %d\n",x,y);
}
reset();
}
return 0;
}

<后记>

『快乐链覆盖 树形dp』的更多相关文章

  1. 『战略游戏 最大利润 树形DP』

    通过两道简单的例题,我们来重新认识树形DP. 战略游戏(luoguP1026) Description Bob喜欢玩电脑游戏,特别是战略游戏.但是他经常无法找到快速玩过游戏的办法.现在他有个问题.他要 ...

  2. 『没有上司的舞会 树形DP』

    树形DP入门 有些时候,我们需要在树形结构上进行动态规划来求解最优解. 例如,给定一颗\(N\)个节点的树(通常是无根树,即有\(N-1\)条无向边),我们可以选择任意节点作为根节点从而定义出每一颗子 ...

  3. 『大 树形dp』

    大 Description 滑稽树上滑稽果,滑稽树下你和我,滑稽树前做游戏,滑稽多又多.树上有 n 个节点,它们构成了一棵树,每个节点都有一个滑稽值. 一个大的连通块是指其中最大滑稽值和最小滑稽值之差 ...

  4. 『You Are Given a Tree 整体分治 树形dp』

    You Are Given a Tree Description A tree is an undirected graph with exactly one simple path between ...

  5. 『kamp 树形dp』

    kamp Description jz 市的云台山是个很美丽的景区,小 x 暑期到云台山打工,他的任务是开景区的大巴. 云台山景区有 N 个景点,这 N 个景点由 N-1 条道路连接而成,我们保证这 ...

  6. 『树上匹配 树形dp』

    树上匹配 Description 懒惰的温温今天上班也在偷懒.盯着窗外发呆的温温发现,透过窗户正巧能看到一棵 n 个节点的树.一棵 n 个节点的树包含 n-1 条边,且 n 个节点是联通的.树上两点之 ...

  7. 【bzoj1907】树的路径覆盖 树形dp

    题目描述 输入 输出 样例输入 1 7 1 2 2 3 2 4 4 6 5 6 6 7 样例输出 3 题解 树形dp 设f[x]表示以x为根的子树完成路径覆盖,且x为某条路径的一端(可以向上延伸)的最 ...

  8. (中等) HDU 5293 Tree chain problem,树链剖分+树形DP。

    Problem Description   Coco has a tree, whose vertices are conveniently labeled by 1,2,…,n.There are ...

  9. 『保卫王国 树上倍增dp』

    保卫王国 Description Z 国有n座城市,n - 1条双向道路,每条双向道路连接两座城市,且任意两座城市 都能通过若干条道路相互到达. Z 国的国防部长小 Z 要在城市中驻扎军队.驻扎军队需 ...

随机推荐

  1. js-深拷贝浅拷贝

    深拷贝浅拷贝可以考察一个人的很多方面,例如:基本功,逻辑能力,编码能力: 在实际工作中的应用:比如用于页面展示的数据状态,与需要传给后端的数据包中,有部分字段的值不一致的话,就需要在传参时根据接口文档 ...

  2. 中国爬虫违法违规案例汇总github项目介绍

    中国爬虫违法违规案例汇总github项目介绍 GitHub - 本项目用来整理所有中国大陆爬虫开发者涉诉与违规相关的新闻.资料与法律法规.致力于帮助在中国大陆工作的爬虫行业从业者了解我国相关法律,避免 ...

  3. swift混编

    http://blog.csdn.net/fengsh998/article/details/34440159

  4. Codeforces Round #590 (Div. 3) F

    传送门 题意: 给出一个只含前\(20\)个字符的字符串,现在可以选择一段区间进行翻转,问区间中字符各不相同时,最长长度为多少. 思路: 首先,容易将题意转换为选择两个字符各不相同的区间,然后长度相加 ...

  5. JS高阶---闭包(循环遍历+监听)

    大纲: 主体: (1)场景1:点击按钮显示点击的第几个 注意:伪数组每次循环时都会重新计算一次长度,所以最好提出去或者直接加到for循环内部 结果: 分析: 1.i为全局变量 解决方案: 1.下标法 ...

  6. 201871010133 赵永军《面向对象程序设计(java)》第六、七周学习总结

    201871010133 赵永军<面向对象程序设计(java)>第六.七周学习总结 项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ ...

  7. uiautomator输入中文实例

    package com.demo3; import jp.jun_nama.test.utf7ime.helper.Utf7ImeHelper; import com.android.uiautoma ...

  8. JWT权限设计思维导图

  9. Maven仓库与坐标(五)

    一.Maven仓库 存放依赖的一个位置/文件夹/仓库,分为以下几种: 本地仓库 中央仓库 远程仓库 1. 本地仓库 第一次执行maven命令时被创建,maven运行时需要的构件都从本地仓库获取,本地仓 ...

  10. luoguP3312 [SDOI2014]数表

    题意 默认\(n\leqslant m\). 设\(f(i)\)表示\(i\)的约数和,因为是积性函数,可以用线性筛求. 先不考虑\(a\)的限制,我们推下式子: \(\sum\limits_{i=1 ...