BZOJ4316 小C的獨立集 【仙人掌】
阿新 • • 發佈:2018-01-28
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的獨立集 【仙人掌】