Gym - 100502G Outing (强连通缩点+树形依赖背包)
问题:有n个人,最多选k个,如果选了某个人就必须选他指定的另一个人,问最多能选多少个人。
将每个人所指定的人向他连一条单向边,则每一个点都有唯一的前驱,形成的图是个基环树森林,在同一个强连通分量里的点要么全选,要么全不选。
首先用Tarjan算法将每个强连通分量(基环树上的环)缩成一个点,这样每棵基环树就变成了普通的树了。
定义每颗树上没有入度的点为树根,建立一个虚根与每棵树的根连一条边,将森林转化成树,对根节点求一遍树形背包即可。
树形依赖背包是树形背包的一个特例,即树形背包在根节点上的dp值。
可用siz数组或者bitset优化。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=+;
int hd[N],op[N],ne,n,k,dp[N][N],dg[N],siz[N],mx[N],dfn[N],low[N],scc[N],sta[N],tot,nscc,tp;
struct E {int v,nxt;} e[N<<];
void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++,dg[v]++;}
void Tarjan(int u) {
low[u]=dfn[u]=++tot;
sta[++tp]=u;
int v=op[u];
if(!dfn[v])Tarjan(v),low[u]=min(low[u],low[v]);
else if(!scc[v])low[u]=min(low[u],dfn[v]);
if(low[u]==dfn[u])for(nscc++; !scc[u]; scc[sta[tp--]]=nscc);
}
void getscc() {
memset(scc,,sizeof scc);
memset(dfn,,sizeof dfn);
nscc=tot=,tp=-;
for(int i=; i<=n; ++i)if(!dfn[i])Tarjan(i);
memset(siz,,sizeof siz);
memset(dg,,sizeof dg);
for(int i=; i<=n; ++i)siz[scc[i]]++;
for(int u=; u<=n; ++u) {
int v=op[u];
if(scc[v]!=scc[u])addedge(scc[v],scc[u]);
}
for(int i=; i<=nscc; ++i)if(!dg[i])addedge(,i);
}
void dfs(int u) {
memset(dp[u],,sizeof dp[u]);
dp[u][siz[u]]=;
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
dfs(v);
for(int j=siz[u]; j>=; --j)if(dp[u][j])
for(int k=; k<=siz[v]; ++k)if(dp[v][k])
dp[u][j+k]=;
siz[u]+=siz[v];
}
} int main() {
memset(hd,-,sizeof hd),ne=;
scanf("%d%d",&n,&k);
for(int i=; i<=n; ++i)scanf("%d",&op[i]);
getscc();
dfs();
for(int i=k; i>=; --i)if(dp[][i]) {printf("%d\n",i); break;}
return ;
}
bitset优化版:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=+;
int hd[N],op[N],ne,n,k,dg[N],siz[N],dfn[N],low[N],scc[N],sta[N],tot,nscc,tp;
bitset<N> dp[N];
struct E {int v,nxt;} e[N];
void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++,dg[v]++;}
void Tarjan(int u) {
low[u]=dfn[u]=++tot;
sta[++tp]=u;
int v=op[u];
if(!dfn[v])Tarjan(v),low[u]=min(low[u],low[v]);
else if(!scc[v])low[u]=min(low[u],dfn[v]);
if(low[u]==dfn[u])for(nscc++; !scc[u]; scc[sta[tp--]]=nscc);
}
void getscc() {
memset(scc,,sizeof scc);
memset(dfn,,sizeof dfn);
nscc=tot=,tp=-;
for(int i=; i<=n; ++i)if(!dfn[i])Tarjan(i);
memset(siz,,sizeof siz);
memset(dg,,sizeof dg);
for(int i=; i<=n; ++i)siz[scc[i]]++;
for(int u=; u<=n; ++u) {
int v=op[u];
if(scc[v]!=scc[u])addedge(scc[v],scc[u]);
}
for(int i=; i<=nscc; ++i)if(!dg[i])addedge(,i);
}
void dfs(int u) {
dp[u].reset();
dp[u].set(siz[u]);
for(int i=hd[u]; ~i; i=e[i].nxt) {
int v=e[i].v;
dfs(v);
bitset<N> t=dp[u];
for(int j=; j<N; ++j)if(dp[v].test(j))dp[u]|=t<<j;
}
} int main() {
memset(hd,-,sizeof hd),ne=;
scanf("%d%d",&n,&k);
for(int i=; i<=n; ++i)scanf("%d",&op[i]);
getscc();
dfs();
for(int i=k; i>=; --i)if(dp[].test(i)) {printf("%d\n",i); break;}
return ;
}
Gym - 100502G Outing (强连通缩点+树形依赖背包)的更多相关文章
- 【bzoj2427】【软件安装】tarjan缩点+树形依赖背包
(上不了p站我要死了,侵权度娘背锅) Description 现在我们的手头有N个软件,对于一个软件i,它要占用Wi的磁盘空间,它的价值为Vi.我们希望从中选择一些软件安装到一台磁盘容量为M计算机上, ...
- BZOJ.4182.Shopping(点分治/dsu on tree 树形依赖背包 多重背包 单调队列)
BZOJ 题目的限制即:给定一棵树,只能任选一个连通块然后做背包,且每个点上的物品至少取一个.求花费为\(m\)时最大价值. 令\(f[i][j]\)表示在点\(i\),已用体积为\(j\)的最大价值 ...
- BZOJ.4910.[SDOI2017]苹果树(树形依赖背包 DP 单调队列)
BZOJ 洛谷 \(shadowice\)已经把他的思路说的很清楚了,可以先看一下会更好理解? 这篇主要是对\(Claris\)题解的简单说明.与\(shadowice\)的做法还是有差异的(比如并没 ...
- bzoj4753: [Jsoi2016]最佳团体(分数规划+树形依赖背包)
菜菜推荐的“水题”虐了我一天T T...(菜菜好强强qwq~ 显然是个分数规划题,二分答案算出p[i]-mid*s[i]之后在树上跑依赖背包,选k个最大值如果>0说明还有更优解. 第一次接触树形 ...
- RNQOJ [stupid]愚蠢的矿工(树形依赖背包)
题意 题目链接 Sol 树形依赖背包板子题 树形依赖背包大概就是说:对于一个点,只有选了它的父亲才能选自身 把dfs序建出来,倒过来考虑 设\(f[i][j]\)表示从第\(i\)个节点往后背包体积为 ...
- 【LuoguP1273有线电视网】树形依赖背包
参考论文http://wenku.baidu.com/view/8ab3daef5ef7ba0d4a733b25.html 参考一篇写的很好的博文http://www.cnblogs.com/GXZC ...
- Codeforces Gym100502G:Outing(缩点+有依赖的树形背包)
http://codeforces.com/gym/100502/attachments 题意:有n个点,容量为tol,接下来n个关系,表示选了第i个点,那么第xi个点就必须被选.问最多可以选多少个点 ...
- AcWing 286. 选课 (树形依赖分组背包)打卡
有依赖的背包 首先依赖的概念,就是一个东西依附与一个东西之上,我们想买附品的话必须要把主品先买下来,这个可以先做下这道题 https://www.cnblogs.com/Lis-/p/11047466 ...
- CodeForcesGym 100502G Outing
Outing Time Limit: 1000ms Memory Limit: 524288KB This problem will be judged on CodeForcesGym. Origi ...
随机推荐
- 2015.7.7——跌停板做T,就算要搏跌停反弹也要看卖一档压力啊
1.今天中色股份和以往不同买卖盘为正!————今天要重新观察这种新常态下的盘面运作 是否会出现如2015.7.6中描述的“前期错过了皮城中的黄金买点,...其实只要买卖盘为负,后期还会有再次尝试该低点 ...
- Linux服务器iops性能测试-fio
FIO是测试IOPS的非常好的工具,用来对硬件进行压力测试和验证,支持13种不同的I/O引擎,包括:sync,mmap, libaio, posixaio, SG v3, splice, null, ...
- iOS 52个技巧学习心得笔记 第二章 对象 , 消息, 运行期
1. 属性 在开发过程中经常要用到定义属性,@property和@synthesize是经常用到的属性, property在.h文件中作声明,@synthesize在.m文件中用于实现 // Stud ...
- Oracle网络服务管理与配置
一.Oracle网络服务概述 1.网络解决方案. (1)可连接性:在Oracle中,由Oracle net组件负责在客户端应用程序与数据服务器之间创建会话.维护会话连接和数据传输. (2)可管理性: ...
- grads 读取shp
自从GrADS2.0.a8版本开始,GrADS引入了对shp图形的支持,关于此格式在这里不多说, 于是今晚就简单测试了一下最简单画图和查询命令(后续还将测试输出shp图形的命令) 测试数据采用的 ...
- Linux基本命令 文件搜索命令
1.文件搜索命令find ================================================================================== 命令名称 ...
- RHEL(或CentOS)中关于逻辑卷( Logical Volume Manager,LVM)的一些概念及使用LVM的例子
1.逻辑卷(logical volumes,LV) 卷管理在物理存储之上的抽象层,它使你能够创建逻辑存储卷.和直接使用物理存储相比,这从很多方面提供了更大的灵活性.比如,使用逻辑卷,你将不再受物理磁盘 ...
- UNIX 系统常用管理命令
一. 引言 UNIX系统作为一种强大的多用户分时操作系统,在越来越多的场合受到了应用,同时,对UNIX的系统管理的要求也随之越来越多,但目前的书籍对UNIX系统管理命令介绍的并不是很多.本文主要是针对 ...
- Docker容器技术-自动化部署
一.用Chef自动化部署Docker 1.为什么需要自动化部署? Docker引擎需要配置很多参数(cgroups.内存.CPU.文件系统等) 识别Docker容器运行在哪个宿主机上 耗时且容易出错, ...
- Python编程-多态、封装、特性
一.多态与多态性 1.多态 (1)什么是多态 多态指的是一类事物有多种形态,(一个抽象类有多个子类,因而多态的概念依赖于继承) 序列类型有多种形态:字符串,列表,元组. 动物有多种形态:人,狗,猪 文 ...