题目链接
(BZOJ) https://www.lydsy.com/JudgeOnline/problem.php?id=4042
(Luogu) https://www.luogu.org/problem/P4757
题解
挺神仙的题。
观察到两个重要性质:
(1) 只有不影响任何已选方案的时候,才需要去考虑是否要选择\(u\)的子树内往上走的链。(因为链不带权值)
(2) 如果要选择\(u\)子树内往上走的链,那么最多选择一条。
由此可知,我们可以记录哪些链在\(u\)子树内的所有方案中是必选的,所有非必选的都可视作空闲。因为往上走的链最多选择一条,所以如果这条链和一条非必选的边冲突,有办法调整最优方案使得这条链选上,而不会受到“两条非必选的边至少选一条”这种情况的影响。
于是我们记录\(dp[u]\)表示\(u\)子树内最多选择多少链以及\(S[u]\)表示\(u\)子树内最优解非必选的端点,转移的时候先把所有的儿子拿出来,建一个图,两点\(i,j\)连边当且仅当存在\(x\in S[i],y\in S[j], x,y\)是输入的一条路径,然后用状压DP求它的最大匹配即可。设\(dp0[i]\)表示\(i\)集合内的最大匹配,\(U\)为所有儿子的全集,那么若\(dp0[U]=dp0[U-\{i\}]\)就说明\(i\)非必选,那么把\(S[i]\)加入到\(S[u]\)中。
注意特殊处理以\(u\)为一条链的端点的情况。
时间复杂度\(O(n^2+nd2^d+m)\).
代码
#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<cassert>
#include<vector>
using namespace std;
const int N = 1000;
const int M = 5e5;
const int D = 10;
int lg2[(1<<D)+3];
struct Edge
{
int v,nxt;
} e[(N<<1)+3];
int fe[N+3];
int fa[N+3];
bool a[N+3][N+3];
vector<int> ac[N+3];
int dp[N+3];
vector<int> son;
bool ae[D+3][D+3];
bool ae0[D+3];
int dp0[(1<<D)+3];
int n,en,m;
void addedge(int u,int v)
{
en++; e[en].v = v;
e[en].nxt = fe[u]; fe[u] = en;
}
void dfs(int u)
{
dp[u] = 0;
for(int i=fe[u]; i; i=e[i].nxt)
{
int v = e[i].v;
if(v==fa[u]) continue;
fa[v] = u;
dfs(v);
dp[u] += dp[v];
}
son.clear();
for(int i=fe[u]; i; i=e[i].nxt)
{
int v = e[i].v;
if(v==fa[u]) continue;
son.push_back(v);
}
for(int i=0; i<son.size(); i++)
{
for(int j=i+1; j<son.size(); j++)
{
ae[i][j] = ae[j][i] = false;
for(int ii=0; ii<ac[son[i]].size(); ii++)
{
for(int jj=0; jj<ac[son[j]].size(); jj++)
{
if(a[ac[son[i]][ii]][ac[son[j]][jj]])
{
ae[i][j] = ae[j][i] = true; break;
}
}
}
}
ae0[i] = false;
for(int ii=0; ii<ac[son[i]].size(); ii++) {if(a[ac[son[i]][ii]][u]) {ae0[i] = true; break;}}
}
dp0[0] = 0;
for(int i=1; i<(1<<son.size()); i++)
{
int x = lg2[i&(-i)];
dp0[i] = dp0[i^(1<<x)];
if(ae0[x]) {dp0[i]++;}
for(int j=0; j<son.size(); j++)
{
if(i&(1<<j))
{
if(ae[x][j]) {dp0[i] = max(dp0[i],dp0[i^(1<<x)^(1<<j)]+1);}
}
}
}
dp[u] += dp0[(1<<son.size())-1];
for(int i=0; i<son.size(); i++)
{
if(dp0[(1<<son.size())-1]==dp0[((1<<son.size())-1)^(1<<i)])
{
for(int j=0; j<ac[son[i]].size(); j++) {ac[u].push_back(ac[son[i]][j]);}
}
}
ac[u].push_back(u);
}
int main()
{
for(int i=0; i<=D; i++) lg2[1<<i] = i;
int T; scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=1; i<n; i++)
{
int u,v; scanf("%d%d",&u,&v);
addedge(u,v); addedge(v,u);
}
scanf("%d",&m);
for(int i=1; i<=m; i++)
{
int u,v; scanf("%d%d",&u,&v);
a[u][v] = a[v][u] = 1;
}
dfs(1);
printf("%d\n",dp[1]);
for(int i=1; i<=n; i++) fe[i] = fa[i] = 0,ac[i].clear();
for(int i=1; i<=en; i++) e[i].v = e[i].nxt = 0;
for(int i=1; i<=n; i++) for(int j=1; j<=n; j++) a[i][j] = a[j][i] = 0;
n = en = m = 0;
}
return 0;
}
相关推荐
树形数位动态规划是一种在树状结构上进行动态规划的方法,主要应用于解决与树的节点权值和路径相关的优化问题。在这个主题中,我们将会深入探讨几种与树形数位动态规划相关的经典问题和解决方案。 首先,让我们看一...
【BZOJ第一部分】 BZOJ,全称为“北京邮电大学在线评测系统”(Beijing Zhiyuan Online Judge),是中国最早的一批在线编程竞赛平台之一,它为编程爱好者提供了一个练习和检验编程技能的环境。在这个系统中,用户...
BZOJ的题目涉及了计算机科学中的核心算法,如贪心算法、回溯法、分治策略、最短路径算法(Dijkstra和Floyd-Warshall)、最小生成树(Prim和Kruskal)、字符串匹配(KMP和Boyer-Moore)等。通过解决这些题目,不仅...
八中OJ,又简作BZOJ,以原题巨多而著称,该数据为BZOJ上的1000-1109和1130-1139的测试数据节点,没有题目,有需要题目的可以到https://hydro.ac/d/bzoj/p网站查找对应的题目。
【BZOJ第二部分】是针对BZOJ(北京邮电大学在线评测系统)的一个专题,这个专题主要涵盖了BZOJ平台上的P2001到P3000之间的编程题目。对于想要深入学习算法、提升编程能力的IT从业者或学生来说,这是一个宝贵的资源...
【BZOJ第四部分】是针对BZOJ(北京邮电大学在线评测系统)的一个专题,这个专题包含了从P4001到P4406的题目,为用户提供了一个离线做题的资源包。BZOJ是编程爱好者和算法竞赛选手常用来练习和检验自己编程能力的平台...
BZOJ JOI 2013~2014 春季training合宿 系列题解1 本文主要讲述哈希算法在OJ系统中的应用,通过对BZOJ JOI 2013~2014 春季training合宿 系列题解1的分析,来阐述哈希算法的原理和实现。 首先,我们来看一下哈希算法...
【标题】"BZOJ全代码"所指的是一份包含BZOJ(BestCoder Zhijiang Online Judge)平台所有编程题目解决方案的压缩文件。BZOJ是一个在线编程竞赛平台,它提供了大量的算法题目供参赛者练习和提交代码,以检验编程能力...
bzoj部分数据.
BZOJ原题-BZOJP3001-P4000的题目,下载后可以离线做题。
标题"BZOJ3230相似子串测试数据"指的是一个与在线判题平台BZOJ(BestCoder ZOJ,中国大学算法竞赛在线评测系统)相关的编程问题,具体问题编号为3230,涉及的主要知识点是"相似子串"的搜索和处理。在编程竞赛中,...
【标题】"bzoj1878数据"是一个在线编程竞赛中的题目数据集,它主要涉及的问题是利用莫队算法(Mo's Algorithm)来解决特定的计算问题。莫队算法,又称莫队法,是一种处理在线询问的高效算法,尤其在处理区间查询和...
【标题】"bzoj problem" 指的是“八中OJ(Online Judge)问题集”,这是一个在线编程竞赛平台的题目合集。八中OJ可能是某所中学的在线编程训练系统,它提供了大量的编程题目供用户练习和挑战,以提升编程能力和算法...
【CreationAugust的BZOJ代码合集】是一个包含由知名信息学竞赛选手CreationAugust编写的算法和问题解决方案的集合。BZOJ(BestCoder Judge Online)是中国著名的在线评测系统,主要用于信息学奥林匹克(OI)的训练和...
【标题】"Node.js-ZOJCH是BZOJ题库的离线版"揭示了这个项目的核心功能,即提供一个基于Node.js平台的离线版本的BZOJ(BestCoder Judging System)题库。BZOJ是一个在线编程竞赛平台,而ZOJCH则允许用户在没有网络...
【标题】"BZOJ十连测题面" 涉及的是中国信息技术奥林匹克竞赛(OI)中的在线判题系统BZOJ的一系列题目。OI是针对中学生的编程竞赛,旨在提升他们的计算机科学素养和算法设计能力。BZOJ作为国内知名的在线评测系统,...
### BZOJ1034 题解分析 #### 题目概述 题目编号为BZOJ1034的问题,通过一种独特的贪心算法进行解答。本题涉及两个队伍之间的对抗,每个队伍都有自己的实力排序。目标是最大化己方得分。 #### 解题思路与核心代码...
「BZOJ1053」反素数详解 「BZOJ1053」反素数问题是数论领域中的一个经典问题,该问题要求我们计算不超过N的最大反质数。所谓反质数,即满足对所有0,g(x)>g(i)的自然数x,其中g(x)表示x的约数个数。 首先,我们...
bzoj FFT 的模版
CTSC 2011 无穷图的桥(BZOJ 2307) 题解.ppt