【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
传送门 题目大意: 给一颗重新编号,叶子节点的值定义为他到根节点编号的最小值,求所有叶子节点值的乘积的最大值. 题目分析: 为什么我觉得这道题最难的是贪心啊..首先要想到 在一条链上,深度大的编号要小 ...
随机推荐
- jq weui 图片浏览器Photo Browser 第一次点击任意图片总是显示第一张
第一次做这个图片浏览器的时候遇到一个问题,如共有6张图片,每次进入页面时,第一次点击,无论去点击6张图片的哪一张初始化显示的都是第一张图片.后面的每次点击都没有问题的. for(let i = 0;i ...
- java数组之二分法查找
认识: 猜字游戏 步数 所猜的数 结果 可能值的范围 0 1~100 1 50 太高 1~49 2 25 太低 26~49 3 37 太高 26~36 4 31 太低 32~36 5 34 太 ...
- vue学习笔记-:class
当items.state为true时使用class='rad2state',否则为rad2(默认).
- JavaScript编码加密
网上看到的加密方法: JavaScript中有三个可以对字符串编码的函数,分别是: escape,encodeURI,encodeURIComponent,相应3个解码函数:unescape,deco ...
- python__基础 : 类的__new__方法与实现一个单例
__new__ : 这个方法的作用主要是创建一个实例,在创建实例时首先会调用 __new__方法 ,然后调用__init__对实例进行初始化, 如果想修改 __new__ 这个方法,那么最后要 ret ...
- Drazil and Tiles CodeForces - 516B (类拓扑)
Drazil created a following problem about putting 1 × 2 tiles into an n × m grid: "There is a gr ...
- C语言进阶——浮点数的秘密03
浮点数在内存中的储存方式为:符号位 指数位 尾数 float和double类型的数据在计算机内部的表实方法是一样的,但是由于所占的存贮空间的不同,其分别能表示的数值范围和精度不同. 类型 f符号位 指 ...
- POJ:3262-Protecting the Flowers
Protecting the Flowers Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 8606 Accepted: 347 ...
- 【文件处理】RandomAccessFile
一,RandomAccessFile的用途: 使用RandomAccessFile的最大好处在于,一般的InputStream和OutputStream类对于文件都是顺序读取的,不能跳跃读取数据.而R ...
- Nginx 高级配置
nginx官方网站:http://nginx.org/ 1. Nginx连接后端的方式:反向代理(proxy_pass).直连fastcgi(fastcgi_pass) 例子: fastcgi_pa ...