【BZOJ4042】【CERC2014】parades 状压DP
题目大意
给你一棵\(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的更多相关文章
- BZOJ 4042 Luogu P4757 [CERC2014]Parades (树形DP、状压DP)
题目链接 (BZOJ) https://www.lydsy.com/JudgeOnline/problem.php?id=4042 (Luogu) https://www.luogu.org/prob ...
- BZOJ 1087: [SCOI2005]互不侵犯King [状压DP]
1087: [SCOI2005]互不侵犯King Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3336 Solved: 1936[Submit][ ...
- nefu1109 游戏争霸赛(状压dp)
题目链接:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1109 //我们校赛的一个题,状压dp,还在的人用1表示,被淘汰 ...
- poj3311 TSP经典状压dp(Traveling Saleman Problem)
题目链接:http://poj.org/problem?id=3311 题意:一个人到一些地方送披萨,要求找到一条路径能够遍历每一个城市后返回出发点,并且路径距离最短.最后输出最短距离即可.注意:每一 ...
- [NOIP2016]愤怒的小鸟 D2 T3 状压DP
[NOIP2016]愤怒的小鸟 D2 T3 Description Kiana最近沉迷于一款神奇的游戏无法自拔. 简单来说,这款游戏是在一个平面上进行的. 有一架弹弓位于(0,0)处,每次Kiana可 ...
- 【BZOJ2073】[POI2004]PRZ 状压DP
[BZOJ2073][POI2004]PRZ Description 一只队伍在爬山时碰到了雪崩,他们在逃跑时遇到了一座桥,他们要尽快的过桥. 桥已经很旧了, 所以它不能承受太重的东西. 任何时候队伍 ...
- bzoj3380: [Usaco2004 Open]Cave Cows 1 洞穴里的牛之一(spfa+状压DP)
数据最多14个有宝藏的地方,所以可以想到用状压dp 可以先预处理出每个i到j的路径中最小权值的最大值dis[i][j] 本来想用Floyd写,无奈太弱调不出来..后来改用spfa 然后进行dp,这基本 ...
- HDU 1074 Doing Homework (状压dp)
题意:给你N(<=15)个作业,每个作业有最晚提交时间与需要做的时间,每次只能做一个作业,每个作业超出最晚提交时间一天扣一分 求出扣的最小分数,并输出做作业的顺序.如果有多个最小分数一样的话,则 ...
- 【BZOJ1688】[Usaco2005 Open]Disease Manangement 疾病管理 状压DP
[BZOJ1688][Usaco2005 Open]Disease Manangement 疾病管理 Description Alas! A set of D (1 <= D <= 15) ...
随机推荐
- python中类方法,实例方法,静态方法的作用和区别
Python中至少有三种比较常见的方法类型,即实例方法,类方法.静态方法.它们是如何定义的呢?如何调用的呢?它们又有何区别和作用呢?且看下文. 首先,这三种方法都定义在类中.下面我先简单说一下怎么 ...
- rest-framework总结
1. CBV: pass 2 .APIView class BookView(APIView):pass url(r'^books/$', views.BookView.as_view(),name= ...
- Python之random模块
random模块 产生随机数的模块 是Python的标准模块,直接导入即可 import random 1)随机取一个整数,使用.randint()方法: import random print(ra ...
- Linux sed使用方法
目录 sed处理流程 测试数据 sed命令格式 sed命令行格式 行定位 定位1行 定位区间行(多行) 定位某一行之外的行 定位有跨度的行 操作命令 -a (新增行) -i(插入行) -c(替代行) ...
- php常用方法
在日常开发中,经常我们使用系统方法或者是自己封装的方法进行项目的开发.再此总结一下!!! 一.对于字符串截取 1.使用mbstring扩展 (注意编码的设置) mb_substr($str,2,5, ...
- vue单页面模板说明文档(1)
Introduction This boilerplate is targeted towards large, serious projects and assumes you are somewh ...
- 如何入门vue之二
学习完指令之后我们需要学习的就是组件. 在学习组件前我们要了解一下 methods 用来处理事件的. computed用来计算属性 他就是类似于data一样只不过是动态的处理数据 里面写的方法当成属 ...
- oracle服务端安装与配置
从oracle官网下载oracle服务端的安装包. 下载下来是两个压缩文件,两个压缩文件都解压(缺一不可)到同一目录下,最后会得到一个database文件夹. 双击database文件夹下的setup ...
- Oracle 表空间不足引起的问题及解决方法
-- 1 向数据库导入数据时报了ORA-01653: unable to extend table错误,网上查了下原因是由于表空间不足引起的: 查询表空间使用情况语句 select a.tablesp ...
- Oracle转换函数
()--转换函数 --数字转换字符串 )||'分' from dual; ||'' from dual; ()--日期转字符串 select to_char(sysdate,'yyyy-mm-dd') ...