仙人掌 之 最大独立集
/************************************************************** Problem: 4316 User: lxy8584099 Language: C++ Result: Accepted Time:232 ms Memory:8744 kb ****************************************************************/ /* 仙人掌 之 独立集 建树。。。 试着能不能边建树 边处理方点 方点处理 断掉环的最后一条边, 强制选择环顶不选择环底, 再强制选择环底不选择环顶, 做两遍即可。 */ #include<cstdio> #include<cstring> #define inf (0x3fffffff) #define min(a,b) ((a>b)?(b):(a)) #define max(a,b) ((a>b)?(a):(b)) using namespace std; const int N=100050; struct pp {int nxt,v;} e[N<<2]; int head[N],tot=1,n,m; int low[N],dfn[N],fa[N],f[N][2],g[N][2],q[N],top; void Add(int u,int v) { e[++tot].nxt=head[u];head[u]=tot;e[tot].v=v; e[++tot].nxt=head[v];head[v]=tot;e[tot].v=u; } void Init() { scanf("%d%d",&n,&m); for(int i=1,u,v;i<=m;i++) scanf("%d%d",&u,&v),Add(u,v); } void Work(int u,int v) { q[top=1]=v; for(int i=v;i!=u;i=fa[i]) q[++top]=fa[i]; g[v][0]=f[v][0];g[v][1]=-inf; // 强制不选 环的底部 for(int i=2;i<=top;i++) { g[q[i]][0]=f[q[i]][0]; g[q[i]][0]+=max(g[q[i-1]][0],g[q[i-1]][1]); g[q[i]][1]=f[q[i]][1]; g[q[i]][1]+=g[q[i-1]][0]; } int max0=g[u][0],max1=g[u][1]; g[v][0]=f[v][0];g[v][1]=f[v][1]; for(int i=2;i<=top;i++) { g[q[i]][0]=f[q[i]][0]; g[q[i]][0]+=max(g[q[i-1]][0],g[q[i-1]][1]); g[q[i]][1]=f[q[i]][1]; g[q[i]][1]+=g[q[i-1]][0]; } max0=max(max0,g[u][0]); //不更新max1 就是强制不选择环的顶部 f[u][0]=max0;f[u][1]=max1; } void Tarjan(int u) { dfn[u]=low[u]=++tot;f[u][1]=1; f[u][0]=0; for(int j=head[u];j;j=e[j].nxt) { int v=e[j].v; if(v==fa[u]) continue; if(!dfn[v]) { fa[v]=u;Tarjan(v);low[u]=min(low[u],low[v]); if(low[v]>dfn[u]) // 不存在环 { f[u][0]+=max(f[v][0],f[v][1]); f[u][1]+=f[v][0]; } } else low[u]=min(low[u],dfn[v]); } for(int j=head[u];j;j=e[j].nxt) { int v=e[j].v; if(fa[v]!=u&&dfn[u]<dfn[v]) Work(u,v); } } void Solve() { tot=0;Tarjan(1); printf("%d\n",max(f[1][1],f[1][0])); } int main() { Init(); Solve(); return 0; }