1. 程式人生 > >BZOJ4316 小C的獨立集 【仙人掌】

BZOJ4316 小C的獨立集 【仙人掌】

long long ostream bzoj pri cpp () void post 就是

題目

圖論小王子小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的獨立集 【仙人掌】