bzoj 4316: 小C的独立集 — 圆方树,dp
Contents
4316: 小C的独立集
Time Limit: 10 Sec Memory Limit: 128 MB
Description
图论小王子小C经常虐菜,特别是在图论方面,经常把小D虐得很惨很惨。
这不,小C让小D去求一个无向图的最大独立集,通俗地讲就是:在无向图中选出若干个点,这些点互相没有边连接,并使取出的点尽量多。
小D虽然图论很弱,但是也知道无向图最大独立集是npc,但是小C很仁慈的给了一个很有特点的图: 图中任何一条边属于且仅属于一个简单环,图中没有重边和自环。小C说这样就会比较水了。
小D觉得这个题目很有趣,就交给你了,相信你一定可以解出来的。
Input
第一行,两个数n, m,表示图的点数和边数。
第二~m+1行,每行两个数x,y,表示x与y之间有一条无向边。
Output
输出这个图的最大独立集。
Sample Input
5 6
1 2
2 3
3 1
3 4
4 5
3 5
1 2
2 3
3 1
3 4
4 5
3 5
Sample Output
2
HINT
100% n <=50000, m<=60000
Source
emmm直接搞出圆方树然后dp
我们只需要对于方点特殊处理
因为我们发现对于方点向上的更新,如果fa[x]取的话他会由f[x][0]更新,所以f[x][0]实际表示的是x儿子中头尾两个点不取的最优代价,我们可以再dp一下得到
同理,对于f[x][1]表示儿子中不相邻取法的最优代价,一样可以dp求得
#include<map>
#include<cmath>
#include<queue>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define inf 1000000007
#define ll long long
#define N 120010
inline int rd()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,nn;
int dfn[N],tim,fa[N],len[N];
bool vs[N];
struct cst
{
int lj[N],fro[N],to[N],cnt=0;
void add(int a,int b){fro[++cnt]=lj[a];to[cnt]=b;lj[a]=cnt;}
int f[N][2],s[N],sz;
int g[N][2];//表示第i个儿子选或者不选的最大个数
void sol(int x)
{
sz=0;
for(int i=lj[x];i;i=fro[i]) s[++sz]=to[i];
if(sz==2)
{
f[x][0]=f[s[1]][0]+f[s[2]][0];
f[x][1]=max(f[s[1]][0]+f[s[2]][0],max(f[s[1]][0]+f[s[2]][1],f[s[1]][1]+f[s[2]][0]));
return;
}
g[1][0]=f[s[1]][0];g[1][1]=-inf;
for(int i=2;i<=sz;i++)
{
g[i][1]=g[i-1][0]+f[s[i]][1];
g[i][0]=max(g[i-1][1],g[i-1][0])+f[s[i]][0];
}
f[x][0]=g[sz][0];
g[1][0]=f[s[1]][0];g[1][1]=f[s[1]][1];
for(int i=2;i<=sz;i++)
{
g[i][1]=g[i-1][0]+f[s[i]][1];
g[i][0]=max(g[i-1][1],g[i-1][0])+f[s[i]][0];
}
f[x][1]=max(g[sz][0],g[sz][1]);
}
void dfs(int x)
{
f[x][0]=0;
f[x][1]=(x<=nn);
for(int i=lj[x];i;i=fro[i])
{
dfs(to[i]);
if(x<=nn)
{
f[x][0]+=max(f[to[i]][0],f[to[i]][1]);
f[x][1]+=f[to[i]][0];
}
}
if(x>nn) sol(x);
}
void work()
{
dfs(1);
printf("%d\n",max(f[1][0],f[1][1]));
}
}T;
int lj[N],fro[N],to[N],cnt;
void add(int a,int b){fro[++cnt]=lj[a];to[cnt]=b;lj[a]=cnt;}
void tarjan(int x)
{
dfn[x]=++tim;
for(int i=lj[x],tx;i;i=fro[i])
{
if(to[i]==fa[x]) continue;
if(!dfn[to[i]]) fa[to[i]]=x,tarjan(to[i]);
else if(dfn[to[i]]<dfn[x])
{
len[++n]=dfn[x]-dfn[to[i]]+1;
fa[n]=to[i];
T.add(to[i],n);
tx=x;
while(tx^to[i])
{
T.add(n,tx);
vs[tx]=1;
tx=fa[tx];
}
}
}
if(!vs[x]) T.add(fa[x],x);
tim--;
}
int main()
{
nn=n=rd();m=rd();
for(int i=1,x,y;i<=m;i++)
{
x=rd();y=rd();
add(x,y);add(y,x);
}
tarjan(1);
T.work();
return 0;
}
发表评论