本题有两种写法,dfs树上DP和仙人掌DP。

先考虑dfs树DP。

什么是dfs树?其实是对于一棵仙人掌,dfs后形成生成树,找出非树边(即返祖边),然后dfs后每条返祖边+其所覆盖的链构成了一个环(很显然覆盖的链互不相交),然后可以确定每条边出现在哪个环中,然后可以解决一些简单的仙人掌DP问题,不用写tarjan了。

这道题的第一种方法就是dfs树DP,题目是求仙人掌的最大独立集。

首先树形DP,没有环应该很好求,有环的情况,考虑记录环上的点的top和end(注意环顶部不用记录,因为环顶部可能属于另一个环底)。然后可以直接DP了,相比于树形DP多记录一维环底部是否选,改成开两个数组,g[i][0/1]表示强制让环底部不选,该点不选/选的最大值,f[i][0/1]表示无所谓让环底部选不选,该点不选/选的最大值。首先对点u,初始化:f[u][1]=1,若不为环底部,则g[u][1]=1。dfs到边u->v,g[u][1]+=g[v][0],因为无论如何该点选了则儿子、底部势必不选,如果两点不在一个环上,则g[u][0]+=max(f[u][0],f[u][1]),反之g[u][0]+=max(g[v][0],g[v][1])。然后考虑转移f数组,首先f[u][0]+=max(f[v][0],f[v][1]),因为u不选,一切自由,如果u不为环的顶部,则f[u][1]+=f[v][0],反之,底部也不能选,f[u][1]+=g[v][0]。

贴不贴code也无所谓了,都说了这么多,不过还是贴一个吧。

#include<bits/stdc++.h>
using namespace std;
const int N=;
int n,m,dep[N],fa[N],tp[N],ed[N],f[N][],g[N][];
vector<int>G[N];
void dfs(int u)
{
dep[u]=dep[fa[u]]+;
for(int i=;i<G[u].size();i++)if(!dep[G[u][i]])fa[G[u][i]]=u,dfs(G[u][i]);
}
void walk(int u,int v){int x=v;while(x!=u)tp[x]=u,ed[x]=v,x=fa[x];}
void dp(int u)
{
f[u][]=;
if(u!=ed[u])g[u][]=;
for(int i=;i<G[u].size();i++)
if(dep[u]+==dep[G[u][i]])
{
int v=G[u][i];
dp(v);
if(ed[u]!=ed[v])g[u][]+=max(f[v][],f[v][]);else g[u][]+=max(g[v][],g[v][]);
g[u][]+=g[v][];
if(tp[v]!=u)f[u][]+=f[v][];else f[u][]+=g[v][];
f[u][]+=max(f[v][],f[v][]);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=,x,y;i<=m;i++)scanf("%d%d",&x,&y),G[x].push_back(y),G[y].push_back(x);
dfs();
for(int u=;u<=n;u++)
for(int i=;i<G[u].size();i++)
if(dep[u]+<dep[G[u][i]])walk(u,G[u][i]);
dp();
printf("%d",max(f[][],f[][]));
}

这题也可以仙人掌DP,当然不需要建立圆方树。tarjan的本质是构建dfs树,然后f[i][0/1]表示当前节点为i,不选/选的最大值,当边是树边时可以直接转移,反之暂时不转移。等到发现其为环的顶部时,然后从底部向顶部推一遍答案。由于是一条链,维护f0和f1表示当前其不选/选的最大值,然后推两遍即可,注意推一遍求f[u][1]时,强制不选底部,即f1=-inf,然后就是裸的树形DP了

#include<bits/stdc++.h>
using namespace std;
const int N=;
int n,m,cnt,dfn[N],low[N],fa[N],f[N][];
vector<int>G[N];
void dp(int u,int v)
{
int t0,t1,f0=,f1=;
for(int i=v;i!=u;i=fa[i])t0=f0+f[i][],t1=f1+f[i][],f0=max(t0,t1),f1=t0;
f[u][]+=f0;
f0=,f1=-1e9;
for(int i=v;i!=u;i=fa[i])t0=f0+f[i][],t1=f1+f[i][],f0=max(t0,t1),f1=t0;
f[u][]+=f1;
}
void tarjan(int u,int pre)
{
fa[u]=pre,dfn[u]=low[u]=++cnt;
f[u][]=,f[u][]=;
for(int i=;i<G[u].size();i++)
{
int v=G[u][i];
if(!dfn[v])tarjan(v,u),low[u]=min(low[u],low[v]);
else if(v!=pre)low[u]=min(low[u],dfn[v]);
if(low[v]>dfn[u])f[u][]+=f[v][],f[u][]+=max(f[v][],f[v][]);
}
for(int i=;i<G[u].size();i++)if(fa[G[u][i]]!=u&&dfn[u]<dfn[G[u][i]])dp(u,G[u][i]);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=,x,y;i<=m;i++)scanf("%d%d",&x,&y),G[x].push_back(y),G[y].push_back(x);
tarjan(,);
printf("%d",max(f[][],f[][]));
}

bzoj4316小C的独立集(dfs树/仙人掌+DP)的更多相关文章

  1. [BZOJ4316]小C的独立集 仙人掌?

    题目链接 因为xls让我每周模拟一次,然后学习模拟中没有学过的东西.所以就来学圆方树. 本来这道题用不着圆方树,但是圆方树是看yyb的博客学的,他在里面讲一下作为一个引子,所以也来写一下. 首先来Ta ...

  2. 【题解】Bzoj4316小C的独立集

    决定要开始学习圆方树 & 仙人掌相关姿势.加油~~ 其实感觉仙人掌本质上还是一棵树,长得也还挺优美的.很多的想法都可以往树的方面上靠,再针对仙人掌的特性做出改进.这题首先如果是在树上的话那么实 ...

  3. 2018.07.08 hdu4521 小明系列问题——小明序列(线段树+简单dp)

    小明系列问题--小明序列 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others) Proble ...

  4. [BZOJ4316]小C的独立集(圆方树DP)

    题意:求仙人掌图直径. 算法:建出仙人掌圆方树,对于圆点直接做普通的树上DP(忽略方点儿子),方点做环上DP并将值直接赋给父亲. 建图时有一个很好的性质,就是一个方点在邻接表里的点的顺序正好就是从环的 ...

  5. BZOJ4316 小C的独立集 【仙人掌】

    题目 图论小王子小C经常虐菜,特别是在图论方面,经常把小D虐得很惨很惨. 这不,小C让小D去求一个无向图的最大独立集,通俗地讲就是:在无向图中选出若干个点,这些点互相没有边连接,并使取出的点尽量多. ...

  6. 2019.02.07 bzoj4316: 小C的独立集(仙人掌+树形dp)

    传送门 题意:给出一个仙人掌森林求其最大独立集. 思路:如果没有环可以用经典的树形dpdpdp解决. fi,0/1f_{i,0/1}fi,0/1​表示第iii个点不选/选的最大独立集. 然后fi,0+ ...

  7. bzoj4316: 小C的独立集

    Description 图论小王子小C经常虐菜,特别是在图论方面,经常把小D虐得很惨很惨. 这不,小C让小D去求一个无向图的最大独立集,通俗地讲就是:在无向图中选出若干个点,这些点互相没有边连接,并使 ...

  8. 树上独立集数量 树型DP

    题目描述: 对于一棵树,独立集是指两两互不相邻的节点构成的集合.例如,图1有5个不同的独立集(1个双点集合.3个单点集合.1个空集),图2有14个不同的独立集,图3有5536个不同的独立集.  输入: ...

  9. hdu 4521 小明序列(线段树,DP思想)

    题意: ①首先定义S为一个有序序列,S={ A1 , A2 , A3 , ... , An },n为元素个数 : ②然后定义Sub为S中取出的一个子序列,Sub={ Ai1 , Ai2 , Ai3 , ...

随机推荐

  1. XtraReport1添加参数

    解决了在report有个BeforePrint事件这里面直接 C# code   ? 1 string year = this.Parameters["year"].Value.T ...

  2. 前端轻量级、简单、易用的富文本编辑器 wangEditor 的基本用法

    1.富文本编辑器市面上有很多,但是综合考虑之后wangEditor是最易用的框架,推荐使用 首先进入官网 http://www.wangeditor.com 基本是2中方式引入: 使用CDN://un ...

  3. Day6 - M - 动态逆序对 HYSBZ - 3295

    对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删 除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数 I ...

  4. 阿里云安装配置nginx

    一.简介 Nginx是一款轻量级的网页服务器.反向代理服务器.相较于Apache.lighttpd具有占有内存少,稳定性高等优势.它最常的用途是提供反向代理服务. 二 .安装 1.准备工作 Nginx ...

  5. 08 MySQL存储引擎

    查询当前默认存储引擎     SHOW VARIABLES LIKE 'table_type' ;      查询当前数据库支持的引擎有哪些 :     SHOW ENGINES \G   -- 推荐 ...

  6. 02 DML(DataManipulationLanguage)

    1.插入记录     基本语法 :         INSERT INTO tbl_name (col_name ,col_name1,..,col_nameN) VALUES (val1,val2, ...

  7. Oracle-SQL 建表

    建立员工分类表: 员工分类表结构.内容分别如下图:   一.使用PL/SQL Dev 这类可视化工具直接创建表 1.建立表结构 新建-table-名称(egrade)    然后 列:创建表结构 2. ...

  8. 吴裕雄 Bootstrap 前端框架开发——Bootstrap 字体图标(Glyphicons):glyphicon glyphicon-barcode

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name ...

  9. MongoDB Limit

    版权所有,未经许可,禁止转载 章节 MongoDB 入门 MongoDB 优势 MongoDB 安装 MongoDB 数据建模 MongoDB 创建数据库 MongoDB 删除数据库 MongoDB ...

  10. Bean Java配置

    Spring 系列教程 Spring 框架介绍 Spring 框架模块 Spring开发环境搭建(Eclipse) 创建一个简单的Spring应用 Spring 控制反转容器(Inversion of ...