【Luogu】P2465山贼集团(树形状压DP)
写了个70分暴力还挂了,第一遍提交只拿了十分……海星
首先建虚拟节点多叉树转成二叉,然后子集枚举DP
设g[x][i]是以x为根的子树内山贼集合i,x啥都不选也没贡献的时候的最大价值
f[x][i]是要求的答案
然后状压DP即可。
#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<cstdlib>
#define maxn 200
#define maxp 13
using namespace std;
inline long long read(){
long long num=,f=;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-;
ch=getchar();
}
while(isdigit(ch)){
num=num*+ch-'';
ch=getchar();
}
return num*f;
} struct Edge{
int next,to;
}; struct Pic{
Edge edge[maxn*];
int head[maxn*],num;
Pic(){num=;}
void add(int from,int to){
edge[++num]=(Edge){head[from],to};
head[from]=num;
}
}Old,New; int cst[maxn][maxn];
int tot;
int mon[<<maxp];
int dl[maxn],ndl[maxn*];
int f[maxn*][<<maxp];
int g[maxn*][<<maxp];
int cost[maxn][<<maxp];
int vl[<<maxp];
int n,p; void chan(int x,int fa){
int now=x;
for(int i=Old.head[x];i;i=Old.edge[i].next){
int to=Old.edge[i].to;
if(to==fa) continue;
if(ndl[now]==||(ndl[now]==&&dl[x]==)){
New.add(now,to);
ndl[now]++; dl[x]--;
}
else{
New.add(now,++tot);
now=tot;
New.add(now,to);
ndl[now]++; dl[x]--;
}
chan(to,x);
}
} void dfs(int x,int fa){
int lson=,rson=;
f[x][]=;
g[x][]=;
for(int i=New.head[x];i;i=New.edge[i].next){
int to=New.edge[i].to;
if(to==fa) continue;
if(lson==) lson=to;
else rson=to;
dfs(to,x);
}
if(x>n){
if(rson==){
for(int i=;i<(<<p);++i) f[x][i]=g[x][i]=f[lson][i];
return;
}
for(int i=;i<(<<p);++i){
for(int j=i;j;j=(j-)&i)
g[x][i]=max(g[x][i],f[lson][j]+f[rson][i^j]);
g[x][i]=max(g[x][i],f[lson][]+f[rson][i]);
f[x][i]=g[x][i];
}
}
else{
if(rson==){
for(int i=;i<(<<p);++i){
g[x][i]=f[lson][i];
f[x][i]=g[x][i]+mon[i];
}
for(int i=;i<(<<p);++i)
for(int j=i;j;j=(j-)&i)
f[x][i]=max(f[x][i],g[x][i^j]-cost[x][j]+mon[i]);
return;
}
for(int i=;i<(<<p);++i){
for(int j=i;j;j=(j-)&i)
g[x][i]=max(g[x][i],f[lson][j]+f[rson][i^j]);
g[x][i]=max(g[x][i],f[lson][]+f[rson][i]);
f[x][i]=g[x][i]+mon[i];
}
for(int i=;i<(<<p);++i)
for(int j=i;j;j=(j-)&i){
int costx=cost[x][j],state=i^j;
f[x][i]=max(f[x][i],g[x][state]+mon[i]-costx);
} }
} int main(){
memset(f,-/,sizeof(f));
memset(g,-/,sizeof(g));
g[][]=;
f[][]=;
n=read(),p=read();
tot=n;
for(int i=;i<n;++i){
int from=read(),to=read();
Old.add(from,to);
Old.add(to,from);
dl[from]++; dl[to]++;
}
for(int i=;i<=n;++i) dl[i]--;
for(int i=;i<=n;++i)
for(int j=;j<=p;++j) cst[i][j]=read();
int T=read();
while(T--){
int val=read(),cnt=read(),state=;
for(int i=;i<=cnt;++i){
int x=read();
state|=(<<(x-));
}
vl[state]+=val;
}
for(int i=;i<(<<p);++i)
for(int j=i;j;j=(j-)&i) mon[i]+=vl[j];
for(int i=;i<=n;++i)
for(int j=;j<(<<p);++j){
int costx=;
for(int k=;k<=p;++k)
if(j&(<<(k-))) costx+=cst[i][k];
cost[i][j]=costx;
}
chan(,);
dfs(,);
printf("%d\n",f[][(<<p)-]);
}
/*
9 3 1 2
1 3
1 4
2 5
3 6
3 7
3 8
6 9 */
【Luogu】P2465山贼集团(树形状压DP)的更多相关文章
- 『Tree nesting 树形状压dp 最小表示法』
Tree nesting (CF762F) Description 有两个树 S.T,问 S 中有多少个互不相同的连通子图与 T 同构.由于答案 可能会很大,请输出答案模 1000000007 后的值 ...
- 【bzoj4006】[JLOI2015]管道连接 斯坦纳树+状压dp
题目描述 给出一张 $n$ 个点 $m$ 条边的无向图和 $p$ 个特殊点,每个特殊点有一个颜色.要求选出若干条边,使得颜色相同的特殊点在同一个连通块内.输出最小边权和. 输入 第一行包含三个整数 n ...
- bzoj 4006 [JLOI2015]管道连接(斯坦纳树+状压DP)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4006 [题意] 给定n点m边的图,连接边(u,v)需要花费w,问满足使k个点中同颜色的 ...
- 51nod 1673 树有几多愁——虚树+状压DP
题目:http://www.51nod.com/Challenge/Problem.html#!#problemId=1673 建一个虚树. 一种贪心的想法是把较小的值填到叶子上,这样一个小值限制到的 ...
- bzoj1402 Ticket to Ride 斯坦纳树 + 状压dp
给定\(n\)个点,\(m\)条边的带权无向图 选出一些边,使得\(4\)对点之间可达,询问权值最小为多少 \(n \leqslant 30, m \leqslant 1000\) 首先看数据范围,\ ...
- 刷题总结——树有几多愁(51nod1673 虚树+状压dp+贪心)
题目: lyk有一棵树,它想给这棵树重标号. 重标号后,这棵树的所有叶子节点的值为它到根的路径上的编号最小的点的编号. 这棵树的烦恼值为所有叶子节点的值的乘积. lyk想让这棵树的烦恼值最大,你只需输 ...
- bzoj 4006 管道连接 —— 斯坦纳树+状压DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4006 用斯坦纳树求出所有关键点的各种连通情况的代价,把这个作为状压(压的是集合选择情况)的初 ...
- 绿色计算大赛决赛 第二阶段 消息传递(斯坦纳树 状压dp+spfa)
传送门 Description 作为公司老板的你手下有N个员工,其中有M个特殊员工.现在,你有一个消息需要传递给你的特殊员工.因为你的公司业务非常紧张,所以你和员工之间以及员工之间传递消息会造成损失. ...
- 51nod1673 树有几多愁 - 贪心策略 + 虚树 + 状压dp
传送门 题目大意: 给一颗重新编号,叶子节点的值定义为他到根节点编号的最小值,求所有叶子节点值的乘积的最大值. 题目分析: 为什么我觉得这道题最难的是贪心啊..首先要想到 在一条链上,深度大的编号要小 ...
随机推荐
- UVa中国麻将(Chinese Mahjong,Uva 11210)
简单的回溯题 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm ...
- Go单元测试与基准测试
Go单元测试 Go单元测试框架,遵循规则整理如下: 1.文件命名规则: 含有单元测试代码的go文件必须以_test.go结尾,Go语言测试工具只认符合这个规则的文件 单元测试文件名_test.go前面 ...
- css页面出现滚动条左右跳动
问题描述:页面首次加载的时候内容是一屏,不会出现纵向滚动条,但是当点击加载的内容更多时页面会出现左右跳动一下的情况.出现跳动的主要原因就是出现了滚动条,滚动条的宽度影响了内容区域的宽度. 1.查看导航 ...
- 呕心沥血写的python猜数字
#猜数字 import random num_rd=random.randint(0,100) count=1 while 1<=count<=10: num_ip=input('请输入0 ...
- C语言函数篇(四)函数的设计
1. 函数设计的时候,如果使用到全局变量,就尽量通过参数的形式传递进来 也就是说,保持 函数 跟 外部的交互 只有 参数 和 返回值 2. 在有参数的情况下,或者有数值输入的时候,要先进行错误判断. ...
- Hadoop(初始Hadoop)
Hadoop核心组件 1.Hadoop生态系统 Hadoop具有以下特性: 方便:Hadoop运行在由一般商用机器构成的大型集群上,或者云计算服务上 健壮:Hadoop致力于在一般商用硬件上运行,其架 ...
- Azure Cloud Service - PaaS
使用Azure Cloud Service有一段时间了,前阵子在公司内部做一个Cloud Service培训的时候就在想,能不能用一幅图把Cloud Service所涉及的概念都罗列出来.于是就有了下 ...
- 5. css定位 居中
1.准备工作 (1)添加背景图片 background: url('images/grass.png') (2)背景图片格式 background-size:contain; #完全限制在方框 #co ...
- hadoop中namenode发生故障的处理方法
Namenode 故障后,可以采用如下两种方法恢复数据: 方法一:将 SecondaryNameNode 中数据拷贝到 namenode 存储数据的目录: 方法 二: 使用 -importCheckp ...
- Ubuntu设置root密码[repost]
From: http://hi.baidu.com/busybox/item/283e7d31433db7179cc65ef3 安装完Ubuntu后在终端使用命令:su -然后输入密码,总是不正确.原 ...