题目

图论小王子小C经常虐菜,特别是在图论方面,经常把小D虐得很惨很惨。

这不,小C让小D去求一个无向图的最大独立集,通俗地讲就是:在无向图中选出若干个点,这些点互相没有边连接,并使取出的点尽量多。

小D虽然图论很弱,但是也知道无向图最大独立集是npc,但是小C很仁慈的给了一个很有特点的图: 图中任何一条边属于且仅属于一个简单环,图中没有重边和自环。小C说这样就会比较水了。

小D觉得这个题目很有趣,就交给你了,相信你一定可以解出来的。

输入格式

第一行,两个数n, m,表示图的点数和边数。

第二~m+1行,每行两个数x,y,表示x与y之间有一条无向边。

输出格式

输出这个图的最大独立集。

输入样例

5 6

1 2

2 3

3 1

3 4

4 5

3 5

输出样例

2

提示

100% n <=50000, m<=60000

题解

假设这是一棵树,设\(f[i][0]\)表示\(i\)节点为根,不选\(i\)的最大数量,\(f[i][1]\)表示选择\(i\)的最大数量

转移就很简单了,不选\(i\),儿子可以选可以不选,选了\(i\),儿子必须选

如果是仙人掌的话,就先忽略环上的点,然后单独考虑环的影响传递到最高点

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
using namespace std;
const int maxn = 50005,maxm = 120005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = (out << 3) + (out << 1) + c - '0'; c = getchar();}
return out * flag;
}
int n,m,h[maxn],ne = 2;
struct EDGE{int to,nxt;}ed[maxm];
void build(int u,int v){
ed[ne] = (EDGE){v,h[u]}; h[u] = ne++;
ed[ne] = (EDGE){u,h[v]}; h[v] = ne++;
}
int f[maxn][2],fa[maxn],dfn[maxn],low[maxn],cnt;
int c[maxn],ci,g[maxn][2];
void DP(int u,int rt){
ci = 0; int ans1,ans2;
for (int i = u; i != rt; i = fa[i]) c[++ci] = i;
g[u][0] = f[u][0]; g[u][1] = 0;
for (int i = 2; i <= ci; i++){
u = c[i];
if (i == 2) g[u][0] = f[u][0] + g[c[i - 1]][0];
else g[u][0] = f[u][0] + max(g[c[i - 1]][0],g[c[i - 1]][1]);
g[u][1] = f[u][1] + g[c[i - 1]][0];
}
ans1 = g[c[ci]][0];
g[c[1]][0] = f[c[1]][0]; g[c[1]][1] = f[c[1]][1];
for (int i = 2; i <= ci; i++){
u = c[i];
g[u][0] = f[u][0] + max(g[c[i - 1]][0],g[c[i - 1]][1]);
g[u][1] = f[u][1] + g[c[i - 1]][0];
}
ans2 = max(g[c[ci]][1],g[c[ci]][0]);
f[rt][1] += ans1;
f[rt][0] += ans2;
}
void dfs(int u){
dfn[u] = low[u] = ++cnt;
f[u][1] = 1;
Redge(u) if ((to = ed[k].to) != fa[u]){
if (!dfn[to]){
fa[to] = u;
dfs(to);
low[u] = min(low[u],low[to]);
}else low[u] = min(low[u],dfn[to]);
if (low[to] > dfn[u]){
f[u][0] += max(f[to][0],f[to][1]);
f[u][1] += f[to][0];
}
}
Redge(u) if (dfn[to = ed[k].to] > dfn[u] && fa[to] != u)
DP(to,u);
}
int main(){
n = read(); m = read();
while (m--) build(read(),read());
int ans = 0;
REP(i,n) if (!dfn[i]){
dfs(i);
ans += max(f[i][0],f[i][1]);
}
printf("%d\n",ans);
return 0;
}

BZOJ4316 小C的独立集 【仙人掌】的更多相关文章

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

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

  2. 【BZOJ-4316】小C的独立集 仙人掌DP + 最大独立集

    4316: 小C的独立集 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 57  Solved: 41[Submit][Status][Discuss] ...

  3. BZOJ 4316: 小C的独立集 仙人掌 + 树形DP

    4316: 小C的独立集 Time Limit: 10 Sec  Memory Limit: 128 MB Description 图论小王子小C经常虐菜,特别是在图论方面,经常把小D虐得很惨很惨. ...

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

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

  5. bzoj4316小C的独立集(dfs树/仙人掌+DP)

    本题有两种写法,dfs树上DP和仙人掌DP. 先考虑dfs树DP. 什么是dfs树?其实是对于一棵仙人掌,dfs后形成生成树,找出非树边(即返祖边),然后dfs后每条返祖边+其所覆盖的链构成了一个环( ...

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

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

  7. bzoj4316: 小C的独立集

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

  8. BZOJ.4316.小C的独立集(仙人掌 DP)

    题目链接 \(Description\) 求一棵仙人掌的最大独立集. \(Solution\) 如果是树,那么 \(f[i][0/1]\) 表示当前点不取/取的最大独立集大小,直接DP即可,即 \(f ...

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

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

随机推荐

  1. noip模拟赛#45

    T1:n<=1e6,求最小的区间包含(1,m)的所有数. =>双指针扫一遍即可 #include<cstdio> #include<cstring> #includ ...

  2. cityspace

    类别的网址:https://blog.csdn.net/u010069760/article/details/77847595 r,g,b:  250 170 160 parking   244 35 ...

  3. python_90_hashlib模块

    #用于加密相关的操作,3.x里代替了2.x中的md5模块和sha模块,主要提供 SHA1, SHA224, SHA256, SHA384, SHA512 ,MD5 算法 import hashlib ...

  4. c++ 读取文件 最后一行读取了两次

    用ifstream的eof(),竟然读到文件最后了,判断eof还为false.网上查找资料后,终于解决这个问题. 参照文件:http://tuhao.blogbus.com/logs/21306687 ...

  5. iOS 多线程编程

    参考文章: iOS多线程编程之NSThread的使用http://blog.csdn.net/totogo2010/article/details/8010231 iOS多线程编程之NSOperati ...

  6. ReactiveCocoa入门-part1

    作为一个iOS开发者,你写的每一行代码几乎都是在响应某个事件,例如按钮的点击,收到网络消息,属性的变化(通过KVO)或者用户位置的变化(通过CoreLocation).但是这些事件都用不同的方式来处理 ...

  7. JavaScript数组之傻傻分不清系列(split,splice,slice)

    因业务场景需求,需要将一个数组截断而不需要影响原数组.这里来理解一下 slice,splice,split slice() 从某个已有的数组返回选定的元素.(JavaScript Array 对象) ...

  8. 51nod——2489 小b和灯泡(打表/平方数)

    这题打表去找因子的个数然后判奇偶也行.预处理O(n) 扫一遍判断O(n). ; i * i <= n; i++){ for(int j = i; i * j <= n; j++){ div ...

  9. C语言实现两数相加2018-09-23

    /*给定两个非空链表来表示两个非负整数.位数按照逆序方式存储,它们的每个节点只存储单个数字.将两数相加返回一个新的链表. 你可以假设除了数字 0 之外,这两个数字都不会以零开头. 示例: 输入:(2 ...

  10. intellij idea 下载安装破解教程

    官网下载:http://www.jetbrains.com/idea/download/#section=windows 选择  Ultimate 版本下载 下载完成后,打开安装 在安装路径位置,可以 ...