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 ...
随机推荐
- $.messager.confirm修改弹出框按钮提示文字
$.messager.confirm 默认提示语为“OK”和“Cancel”.引入中文控件后变为“确定”和“取消” <script src="../js/locale/easyui-l ...
- SpringMVC:学习笔记(4)——处理模型数据
SpringMVC—处理模型数据 说明 SpringMVC 提供了以下几种途径输出模型数据: – ModelAndView: 处理方法返回值类型为 ModelAndView时, 方法体即可通过该对象添 ...
- 01_Hadoop学习笔记内容说明
Hadoop学习笔记内容说明_00 1. 观看云帆大数据梦琪老师的<企业级 Hadoop 1.x 应用开发基础课程>2014年4月左右版本. 2. 博客是在梦琪老师的随堂笔记上改动的, ...
- android camera jni调用
http://www.mamicode.com/info-detail-1002139.html how to compile library of native camera for androi ...
- MySQL数据库基本操作(一)
进入mysql 本地连接: mysql -u用户名 -p 输入密码 qwe123 mysql -uroot -pqwe123 sudo apt-get install mysql-server # p ...
- SDWebImage第三方库学习
1.基本使用方法 //异步下载并缓存 - (void)sd_setImageWithURL:(nullable NSURL *)url NS_REFINED_FOR_SWIFT; //使用占位图片,当 ...
- linux下firefox显示中文乱码的问题
只需要yum install "@Chinese Support" 然后注销,再登录一下,刷新浏览器就可以正常显示中文了,当然前提是浏览器的字符编码为utf-8以及默认显示中文,这 ...
- 39条常见的linux系统管理面试题
1.如何看当前Linux系统有几颗物理CPU和每颗CPU的核数? 答:[root@centos6 ~ 10:55 #35]# cat /proc/cpuinfo|grep -c 'physical i ...
- 为WebBrowser指定IE内核版本(MSIE 7.0)
.Web Browser Control – Specifying the IE Version http://www.west-wind.com/weblog/posts/2011/May/21/W ...
- nodejs mysql 创建连接池
用Nodejs连接MySQL 从零开始nodejs系列文章,将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发.Nodejs框架是基于V8的引擎,是目前速度最快的Javas ...