山贼集团 (group)

题目描述

某山贼集团在绿荫村拥有强大的势力,整个绿荫村由N个连通的小村落组成,并且保证对于每两个小村落有且仅有一条简单路径相连。小村落用阿拉伯数字编号为1,2,3,4,…,n,山贼集团的总部设在编号为1的小村落中。山贼集团除了老大坐镇总部以外,其他的P个部门希望在村落的其他地方建立分部。P个分部可以在同一个小村落中建设,也可以分别建设在不同的小村落中。每个分部到总部的路径称为这个部门的管辖范围,于是这P个分部的管辖范围可能重叠,或者完全相同。在不同的村落建设不同的分部需要花费不同的费用。每个部门可能对他的管辖范围内的小村落收取保护费,但是不同的分部如果对同一小村落同时收取保护费,他们之间可能发生矛盾,从而损失一部分的利益,他们也可能相互合作,从而获取更多的利益。现在请你编写一个程序,确定P个分部的位置,使得山贼集团能够获得最大的收益。

输入

输入文件第一行包含一个整数N和P,表示绿荫村小村落的数量以及山贼集团的部门数量。

接下来N-1行每行包含两个整数X和Y,表示编号为X的村落与编号为Y的村落之间有一条道路相连。(1<=X,Y<=N)

接下来N行,每行P个正整数,第i行第j个数表示在第i个村落建设第j个部门的分部的花费Aij。

然后有一个正整数T,表示下面有T行关于山贼集团的分部门相互影响的代价。(0<=T<=2^p)

最后有T行,每行最开始有一个数V,如果V为正,表示会获得额外的收益,如果V为负,则表示会损失一定的收益。然后有一个正整数C,表示本描述涉及的分部的数量,接下来有C个数,Xi,为分部门的编号(Xi不能相同)。表示如果C个分部Xi同时管辖某个小村落(可能同时存在其他分部也管辖这个小村落),可能获得的额外收益或者损失的收益为的|V|。T行中可能存在一些相同的Xi集合,表示同时存在几种收益或者损失。

输出

输出文件要求第一行包含一个数Ans,表示山贼集团设置所有分部后能够获得的最大收益。

样例输入

2 1
1 2
2
1
1
3 1 1

样例输出

5

提示

数据规模

对于40%的数据,1<=P<=6。

对于100%的数据,1<=N<=100,1<=P<=12,保证答案的绝对值不超过108。


solution

令f[k][S]表示在第k棵子树,安排人员状态为S的最大收益(不一定都在k,也可以在k的子树上安排)。

然后发现暴力转移复杂度很高(穷举儿子的安排状态)。

于是我们考虑在树上背包,得出儿子的最优解。

令g[i][S]表示k的前i棵子树,安排人员状态S的最大收益。

    (v是第i个儿子)

g[top][S]即为所有子树的答案  (共有top个儿子)

cost为在k安排的花费,val为收益

枚举2^n,在枚举每个数真子集

效率O(可以过)

似乎是3^n,但我不会证。。。

枚举子集的方法:

for(int j=i;j>=0;j=((j-1)&i)){//枚举i的子集
.....
if(!j)break;
}
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#define maxn 102
#define inf 1e9
using namespace std;
int n,p,head[maxn],f[maxn][1<<13],g[maxn][1<<13];
int t1,t2,tot,cost[maxn][12],t,tt,top,Max;
struct node{
int v,nex;
}e[maxn*2];
struct no{
int zt,v,num;
}c[1<<13];
void lj(int t1,int t2){
e[++tot].v=t2;e[tot].nex=head[t1];head[t1]=tot;
}
void mer(int a,int id){
if(id==1){
for(int i=0;i<=Max;i++)g[id][i]=f[a][i];
return;
}
for(int i=0;i<=Max;i++){
g[id][i]=-inf;
for(int j=i;j>=0;j=((j-1)&i)){
int S=i-j;
g[id][i]=max(g[id][i],g[id-1][j]+f[a][S]);
if(!j)break;
}
}
}
int co(int fs,int k){
int sum=0;
for(int i=0;i<p;i++){
if((k&(1<<i))>0)sum-=cost[fs][i+1];
}
return sum;
}
int val(int k){
int sum=0;
for(int i=1;i<=t;i++){
int S=k|c[i].zt;
if(S==k)sum+=c[i].v;
}
return sum;
}
void dfs(int k,int fa){
for(int i=head[k];i;i=e[i].nex){
if(e[i].v!=fa){
dfs(e[i].v,k);
}
}
top=1;int fl=0;
for(int i=head[k];i;i=e[i].nex){
if(e[i].v!=fa){
fl=1;mer(e[i].v,top);top++;
}
}
top--;
//cout<<"k "<<k<<' '<<top<<endl;
if(!fl){
for(int i=0;i<=Max;i++){
f[k][i]=co(k,i)+val(i);
//cout<<f[k][i]<<' ';
}
//cout<<endl;
return;
}
//cout<<"fuck\n";
for(int i=0;i<=Max;i++){
f[k][i]=-inf;
for(int j=i;j>=0;j=((j-1)&i)){
int S=i-j;
//cout<<"aaa "<<j<<' '<<S<<' '<<i<<' '<<co(k,j)<<' '<<g[top][S]<<endl;
f[k][i]=max(f[k][i],co(k,j)+g[top][S]);
if(!j)break;
}
//cout<<"fsy "<<i<<' '<<f[k][i]<<endl;
f[k][i]+=val(i); //cout<<"haha "<<f[k][i]<<' '<<i<<' '<<val(i)<<endl ;
}
//cout<<endl;
}
int main()
{ cin>>n>>p;
Max=(1<<p)-1;
for(int i=1;i<n;i++){
scanf("%d%d",&t1,&t2);
lj(t1,t2);lj(t2,t1);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=p;j++){
scanf("%d",&t);
cost[i][j]=t;
}
}
cin>>t;
for(int i=1;i<=t;i++){
scanf("%d%d",&c[i].v,&c[i].num);
for(int j=1;j<=c[i].num;j++){
scanf("%d",&tt);
c[i].zt+=(1<<(tt-1));
}
}
dfs(1,0);
cout<<f[1][Max]<<endl;
return 0;
}

山贼集团 (group)的更多相关文章

  1. P2465 [SDOI2008]山贼集团 dp

    这个题是一道树形dp+状压dp二合一,先预处理每种组合会有什么额外的费用,然后在树上dp就行了. 题干: 题目描述 某山贼集团在绿荫村拥有强大的势力,整个绿荫村由N个连通的小村落组成,并且保证对于每两 ...

  2. [SDOI2008]山贼集团

    题目描述 某山贼集团在绿荫村拥有强大的势力,整个绿荫村由\(N\)个连通的小村落组成,并且保证对于每两个小村落有且仅有一条简单路径相连. 小村落用阿拉伯数字编号为\(1,2,3,4, \dots ,n ...

  3. 【Luogu】P2465山贼集团(树形状压DP)

    题目链接 写了个70分暴力还挂了,第一遍提交只拿了十分……海星 首先建虚拟节点多叉树转成二叉,然后子集枚举DP 设g[x][i]是以x为根的子树内山贼集合i,x啥都不选也没贡献的时候的最大价值 f[x ...

  4. 洛咕 P2465 [SDOI2008]山贼集团

    裸的状压dp. 设f[i][j]表示在i字数内放j集合的分部,直接sb转移. // luogu-judger-enable-o2 #include<bits/stdc++.h> #defi ...

  5. 【[SDOI2008]山贼集团】

    非常好的一道题 树上的状压\(dp\) 根据数据范围我们就能知道这是一道需要状压的题目 所以状态就是\(dp[i][S]\)表示在以\(i\)为根的子树里,选择的状态为\(S\)的最大收益 这个收益只 ...

  6. 【学术篇】SDOI2008 山贼集团

    今天一月一号.. 突然想安利一波我的中二的2017总结... 传送门1:codevs 传送门2:luogu 时限5s和1s的区别(你没看我传送门都给的大牛分站了) 现在不仅线筛.. 有负数的快读都打不 ...

  7. 状压DP入门详解+题目推荐

    在动态规划的题型中,一般叫什么DP就是怎么DP,状压DP也不例外 所谓状态压缩,一般是通过用01串表示状态,充分利用二进制数的特性,简化计算难度.举个例子,在棋盘上摆放棋子的题目中,我们可以用1表示当 ...

  8. [ZT] 酒店大洗脑:最全各大国际酒店集团族谱图

    原文地址: http://www.licai.com/yuedu/201411-62884.html 如果你对各大耳熟能详的国际酒店管理集团还有什么问题,相信今天和你分享的各大酒店集团家族系谱图和最全 ...

  9. poj 2985 The k-th Largest Group 树状数组求第K大

    The k-th Largest Group Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 8353   Accepted ...

随机推荐

  1. java调用摄像头

    http://blog.csdn.net/xing_sky/article/details/43482213 原文地址:http://blog.csdn.net/zajin/article/detai ...

  2. Bootstrap 按钮(Button)插件加载状态

    通过按钮(Button)插件,您可以添加进一些交互.比如控制按钮的状态.或者为其它组件(工具栏)创建按钮组. 加载状态 如需向按钮添加加载状态,只需要简单地向 button 元素添加 data-loa ...

  3. django+xadmin在线教育平台(二)

    老话总是没错的,工欲善其事,必先利其器 教你安装pycharm,mysql,navicat,python相关环境. windows下搭建开发环境 2-1 pycharm,mysql,Navicat安装 ...

  4. php与js的crc32(支持中文)

    代码: <?php function myCrc32($string, $crc = 0) { $table = "00000000 77073096 EE0E612C 990951B ...

  5. 【python学习】新手基础程序练习(二)

    Ι 继续上一节得内容,这里主要是对各种知识的理解以及如何运用. 一.执行 Python 脚本的两种方式 1.把python执行文件加到计算机的环境变量中,然后新建文件把程序写在新文件里,再通过cmd命 ...

  6. CDOJ:1636-梦后楼台高锁,酒醒帘幕低垂(Kruskal+暴力)

    梦后楼台高锁,酒醒帘幕低垂 Time Limit: 3000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others) Submit ...

  7. TI C64X+通用库函数使用手册

    在使用前,当知悉以下几点: 函数进程由手动汇编而成,已充分发挥器件效率.同时TI对外提供C和线性汇编代码 对于个人一些特殊应用,DSPLIB可能会带来额外的cycle消耗 TI DSPLIB依平台和时 ...

  8. 笔记-python-变量作用域

    笔记-python-变量作用域 1.      python变量作用域和引用范围 1.1.    变量作用域 一般而言程序的变量并不是任何对象或在任何位置都可以访问的,访问权限决定于这个变量是在哪里赋 ...

  9. android json 解析 kotlin

    前面 写了一次 kotlin解析json 但是,真的写得太烂,直接删掉了,现在重新整理一下.顺便记录一下今天坑了我很久的小问题. 1.首先从最简单的入手吧 一个json的字符串:=====就叫做jso ...

  10. jvm探秘之三:GC初步

    GC即垃圾收集器,虚拟机的必要组成部分. 不过这里说当然是,hotspot虚拟机(jvm的主要版本)的GC机制,前面说过了jvm的组成部分,那么想当然GC只需要负责方法区和堆就好了,虚拟机栈.本地方法 ...