Description
求一个仙人掌无向图最大独立集。
Sample Input
5 6
1 2
2 3
3 1
3 4
4 5
3 5
Sample Output
2
先建圆方树。
建好后做树形DP。
对于每一个环,将它拆环分两种情况讨论。
其他的点直接树形DP。
圆方树,唔
#include <cstdio>
#include <cstring>
using namespace std;
int _max(int x, int y) {return x > y ? x : y;}
struct edge {
int x, y, next;
} e[130000], c[130000]; int len, cnt, last[51000], lt[110000];
int u, n, id, f[51000][2], fa[51000], dfn[51000];
bool cir[51000];
int sta[51000][2];
void ins(int x, int y) {
e[++len].x = x; e[len].y = y;
e[len].next = last[x]; last[x] = len;
}
void add(int x, int y) {
c[++cnt].x = x; c[cnt].y = y;
c[cnt].next = lt[x]; lt[x] = cnt;
}
void dfs(int x) {
dfn[x] = ++id;
for(int k = last[x]; k; k = e[k].next) {
int y = e[k].y;
if(y != fa[x]) {
if(!dfn[y]) {
cir[x] = 0;
fa[y] = x; dfs(y);
if(!cir[x]) add(x, y), add(y, x);
} else if(dfn[y] < dfn[x]) {
int i = x; n++;
add(i, n), add(n, i);
do {
i = fa[i];
add(n, i), add(i, n);
cir[i] = 1;
} while(i != y);
}
}
}
}
void treedp(int x, int fa) {
if(x <= u) {
f[x][0] = 0, f[x][1] = 1;
for(int k = lt[x]; k; k = c[k].next) {
int y = c[k].y;
if(y != fa) {
treedp(y, x);
if(y <= u) {
f[x][0] += _max(f[y][0], f[y][1]);
f[x][1] += f[y][0];
}
}
}
} else {
int tp = 0;
for(int k = lt[x]; k; k = c[k].next) {
int y = c[k].y;
if(y != fa) treedp(y, x);
} for(int k = lt[x]; k; k = c[k].next) sta[++tp][0] = f[c[k].y][0], sta[tp][1] = f[c[k].y][1];
for(int i = tp - 1; i; i--) sta[i][0] += _max(sta[i + 1][1], sta[i + 1][0]), sta[i][1] += sta[i + 1][0];
f[fa][0] = sta[1][0];
for(int i = 1; i < tp; i++) sta[i][0] -= _max(sta[i + 1][1], sta[i + 1][0]), sta[i][1] -= sta[i + 1][0];
sta[tp][1] = -999999999;
for(int i = tp - 1; i; i--) sta[i][0] += _max(sta[i + 1][1], sta[i + 1][0]), sta[i][1] += sta[i + 1][0];
f[fa][1] = sta[1][1];
}
}
int main() {
int m; scanf("%d%d", &n, &m); u = n;
for(int i = 1; i <= m; i++) {
int x, y; scanf("%d%d", &x, &y);
ins(x, y), ins(y, x);
} dfs(1);
treedp(1, 0);
printf("%d\n", _max(f[1][0], f[1][1]));
return 0;
}