题目大意

  给你一棵\(n\)个点的树和\(m\)条路径要求你找出最多的路径,使得这些路径不共边。特别的,每个点的度数\(\leq 10\)。

  \(n\leq 1000,m\leq \frac{n(n-1)}{2}\)

题解

  先对于每个点把相邻的边编号。

  考虑状压DP。

  设\(f_{i,j}\)为以\(i\)个点的子树内,状态为\(j\)的边的子树内的边也没有选(这些边也没选),所选的最多路径数。

  然后对于每个点有很多种选法,分为两类:1.某条边不选,选对应的子树;2.选\(1\)~\(2\)条边和对应的路径,那么这些路径经过的边都不能选。

  然后直接状压DP。

  对于每个点来说,总共有最多\(O(d^2)\)种转移。考虑每个儿子的贡献,就是\(O(d)\)。

  时间复杂度:\(O(n^2+nd2^d)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<ctime>
#include<utility>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
struct list
{
int t[1000010];
pii v[1000010];
int h[1010];
int n;
void clear()
{
memset(h,0,sizeof h);
n=0;
}
void add(int x,pii y)
{
n++;
v[n]=y;
t[n]=h[x];
h[x]=n;
}
};
list l;
int f[1010][1<<10];
int g[1010];
int c[1010][20];
int d[1010];
int ns[12][12];
int e[1010];
void dfs2(int x,int fa,int t,int s)
{
int fc;
int i;
for(i=1;i<=d[x];i++)
if(c[x][i]==fa)
fc=i;
g[x]=s+f[x][((1<<d[x])-1)^(1<<(fc-1))];
e[x]=t;
for(i=1;i<=d[x];i++)
if(c[x][i]!=fa)
dfs2(c[x][i],x,t,s+f[x][((1<<d[x])-1)^(1<<(fc-1))^(1<<(i-1))]);
}
int dd[1010];
int ff[1010];
int lca[1010][1010];
void dfs(int x,int fa,int dep)
{
ff[x]=fa;
dd[x]=dep;
int i;
for(i=1;i<=d[x];i++)
if(c[x][i]!=fa)
dfs(c[x][i],x,dep+1);
}
int getlca(int x,int y)
{
if(x==y)
return x;
if(lca[x][y])
return lca[x][y];
if(dd[x]>dd[y])
return lca[x][y]=getlca(ff[x],y);
return lca[x][y]=getlca(x,ff[y]);
}
void dp(int x,int fa)
{
int i;
for(i=1;i<=d[x];i++)
if(c[x][i]!=fa)
dp(c[x][i],x);
for(i=1;i<=d[x];i++)
if(c[x][i]!=fa)
dfs2(c[x][i],x,i,0);
memset(ns,0,sizeof ns);
int cx,cy,cs;
for(i=l.h[x];i;i=l.t[i])
{
if(l.v[i].first==x)
{
cx=0;
cy=e[l.v[i].second];
cs=g[l.v[i].second];
}
else if(l.v[i].second==x)
{
cx=e[l.v[i].first];
cy=0;
cs=g[l.v[i].first];
}
else
{
cx=e[l.v[i].first];
cy=e[l.v[i].second];
cs=g[l.v[i].first]+g[l.v[i].second];
}
cs++;
if(cx>cy)
swap(cx,cy);
ns[cx][cy]=max(ns[cx][cy],cs);
}
for(i=1;i<=d[x];i++)
if(c[x][i]!=fa)
{
cx=0;
cy=i;
cs=f[c[x][i]][(1<<d[c[x][i]])-1];
ns[cx][cy]=max(ns[cx][cy],cs);
}
int j,k;
for(i=0;i<=d[x];i++)
for(j=0;j<=d[x];j++)
if(ns[i][j])
{
int s=0;
if(i)
s|=1<<(i-1);
if(j)
s|=1<<(j-1);
for(k=0;k<(1<<d[x]);k++)
if(!(k&s))
f[x][k|s]=max(f[x][k|s],f[x][k]+ns[i][j]);
}
}
void solve()
{
memset(d,0,sizeof d);
int n;
scanf("%d",&n);
int i,j;
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
lca[i][j]=0;
for(i=1;i<=n;i++)
for(j=0;j<(1<<10);j++)
f[i][j]=0;
l.clear();
int x,y;
for(i=1;i<=n-1;i++)
{
scanf("%d%d",&x,&y);
c[x][++d[x]]=y;
c[y][++d[y]]=x;
}
dfs(1,0,1);
int m;
scanf("%d",&m);
for(i=1;i<=m;i++)
{
scanf("%d%d",&x,&y);
l.add(getlca(x,y),pii(x,y));
}
dp(1,0);
int ans=0;
for(i=1;i<=n;i++)
ans=max(ans,f[i][(1<<d[i])-1]);
printf("%d\n",ans);
}
int main()
{
#ifdef DEBUG
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
int t;
scanf("%d",&t);
while(t--)
solve();
return 0;
}

【BZOJ4042】【CERC2014】parades 状压DP的更多相关文章

  1. BZOJ 4042 Luogu P4757 [CERC2014]Parades (树形DP、状压DP)

    题目链接 (BZOJ) https://www.lydsy.com/JudgeOnline/problem.php?id=4042 (Luogu) https://www.luogu.org/prob ...

  2. BZOJ 1087: [SCOI2005]互不侵犯King [状压DP]

    1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3336  Solved: 1936[Submit][ ...

  3. nefu1109 游戏争霸赛(状压dp)

    题目链接:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1109 //我们校赛的一个题,状压dp,还在的人用1表示,被淘汰 ...

  4. poj3311 TSP经典状压dp(Traveling Saleman Problem)

    题目链接:http://poj.org/problem?id=3311 题意:一个人到一些地方送披萨,要求找到一条路径能够遍历每一个城市后返回出发点,并且路径距离最短.最后输出最短距离即可.注意:每一 ...

  5. [NOIP2016]愤怒的小鸟 D2 T3 状压DP

    [NOIP2016]愤怒的小鸟 D2 T3 Description Kiana最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于(0,0)处,每次Kiana可 ...

  6. 【BZOJ2073】[POI2004]PRZ 状压DP

    [BZOJ2073][POI2004]PRZ Description 一只队伍在爬山时碰到了雪崩,他们在逃跑时遇到了一座桥,他们要尽快的过桥. 桥已经很旧了, 所以它不能承受太重的东西. 任何时候队伍 ...

  7. bzoj3380: [Usaco2004 Open]Cave Cows 1 洞穴里的牛之一(spfa+状压DP)

    数据最多14个有宝藏的地方,所以可以想到用状压dp 可以先预处理出每个i到j的路径中最小权值的最大值dis[i][j] 本来想用Floyd写,无奈太弱调不出来..后来改用spfa 然后进行dp,这基本 ...

  8. HDU 1074 Doing Homework (状压dp)

    题意:给你N(<=15)个作业,每个作业有最晚提交时间与需要做的时间,每次只能做一个作业,每个作业超出最晚提交时间一天扣一分 求出扣的最小分数,并输出做作业的顺序.如果有多个最小分数一样的话,则 ...

  9. 【BZOJ1688】[Usaco2005 Open]Disease Manangement 疾病管理 状压DP

    [BZOJ1688][Usaco2005 Open]Disease Manangement 疾病管理 Description Alas! A set of D (1 <= D <= 15) ...

随机推荐

  1. koa2实现session的两种方式(基于Redis 和MySQL)

    一.基于MySQL的实现方式 这种方式需要安装koa-session-minimal和koa-mysql-session两个依赖. 执行 npm install koa-session-minimal ...

  2. Python学习第九篇——while和for的区别

    pets = ['dog','cat','dog','goldfish','cat','rabbit','cat'] print(pets) for pet in pets: print(pet) # ...

  3. mysql处理重复数据

    有些 MySQL 数据表中可能存在重复的记录,有些情况我们允许重复数据的存在,但有时候我们也需要删除这些重复的数据. 防止表中出现重复数据 你可以在MySQL数据表中设置指定的字段为 PRIMARY ...

  4. VO和DO转换(二) BeanUtils

    VO和DO转换(一) 工具汇总 VO和DO转换(二) BeanUtils VO和DO转换(三) Dozer VO和DO转换(四) MapStruct BeanUtils是Spring提供的,通常项目都 ...

  5. yolo buffer is too small for requested array

    yolo.cfg 与 yolo.weights 版本一定要对应, darknet链接 https://github.com/pjreddie/darknet 下载后在cfg文件夹下找到yolov2的配 ...

  6. C#设计模式之10:状态模式

    状态模式 状态模式将合适的Context(上下文)模拟成一个状态机,在这个状态机的内部,由Context来决定整个状态机的状态,再根据不同的状态执行不同的方法.在C#编译器的帮助下,很多语法糖的背后都 ...

  7. 使用css控制文字显示几行并且剩余部分隐藏(移动端和PC端同样适用)

    前言 有些需求需要我们控制一段文本最多显示几行,就像逛淘宝京东的评价楼层一样,有时可能还需要隐藏剩余部分,这样的需求我们怎么来解决呢? 解决办法 我们完全可以使用css来解决这一需求 1. 解决文本显 ...

  8. [转帖]HPE的软件部分到底是谁的?

    英国Micro Focus公司收购惠普旗下软件部门 http://www.gongkong.com/news/201710/369740.html 搞不清楚 现在ALM 到底是谁的资产了.. 据国外媒 ...

  9. K3CLOUD常用数据表

    一.数据库查询常用表 --查询数据表select * from ( select convert(varchar(4000),t1.FKERNELXML.query('//TableName')) a ...

  10. java学习之—链表(2)

    /** * 双端链表操作 * Create by Administrator * 2018/6/14 0014 * 下午 2:05 **/ class Link1 { public long dDat ...