本题有两种写法,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. An attempt was made to call the method com.google.gson.GsonBuilder.setLenient()Lcom/google/gson/GsonBuilder; but it does not exist. Its class, com.google.gson.GsonBuilder, is available from the foll

    SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/G:/sharp/repo ...

  2. Docker基础——从入门到精通

    一个完整的docker由几个部分组成? docker client  docker daemon docker images docker containers 容器是一个存储.运输工具,它能对容器内 ...

  3. python 数据处理 对csv文件进行数据处理

    数据如下图: 用python对数据进行处理: #读取csv文件内容并进行数据处理 import os import csv import datetime import re from itertoo ...

  4. 配置gem5-gpu docker版

    1 安装docker:wget -qO- https://get.docker.com/ | sh,启动服务:sudo service docker start 2 把非root用户添加到docker ...

  5. Oracle 建库

    Oracle得安装就不多说了 不过还是建议直接去官网下  其他渠道可能会导致安装问题  具体自己慢慢体会吧  !  下面主要说下怎么用Oracle建库并且建用户角色 Database configur ...

  6. 吴裕雄--天生自然java开发常用类库学习笔记:同步与死锁

    class MyThread implements Runnable{ private int ticket = 5 ; // 假设一共有5张票 public void run(){ for(int ...

  7. 软件管理-RPM命令管理:安装升级与卸载

    1.包名与包全名 包名 : 操作已经安装的软件包时,使用包名:系统会搜索var/lib/rpm中的数据库 包全名: 操作的包时没有安装的软件包时,使用包全名,而且注意路径 2.RPM安装 切换到光盘p ...

  8. HihoCoder第六周:01背包问题

    01背包问题大二的时候就接触过了,几行关键代码自己也都看过很多遍了,但是很多代码一直都没能理解.所以今天拿表来好好地画一画,弄懂其中的动态规划究竟什么含义. 1038 : 01背包 时间限制:2000 ...

  9. bzoj 4008、4011、1499

    全是扒题解,,,太弱了... 不乱BB了. 4008 #include <bits/stdc++.h> #define LL long long #define lowbit(x) x&a ...

  10. Oracle 新建用户、赋予权限

    1.新建用户 新建用户: create User username Identified by password 修改用户密码: alter User username Identified by p ...