zoukankan      html  css  js  c++  java
  • bzoj4316 小C的独立集

    https://darkbzoj.tk/problem/4316

    求一个仙人掌的最大独立集

    先把他建出圆方树来,每个环选一个点当做“这个环的根”,作为对应方点的父亲,其他换上的点作为这个方点的儿子
    考虑用 (f(u,1/2)) 来表示 (u) 的子树中,(u) 这个点选/不选的最大独立集大小
    如何转移?圆点很好转移,(f(u,0)=sum max(f(v,1),f(v,0)),f(u,1)=1+sum f(v,0))
    至于方点如何转移,要弄清它在此的实际意义,考虑一下这个方点的父亲(环的根)的转移情况
    对于 (f(u,0)),它会为 (f(fa,1)) 产生贡献,那么就要选上环的根,则根旁边的两个点就都不能选。就是环的根以下的部分,不选和环的根相邻的两点,能选出的最大独立集大小
    对于 (f(u,1)),它只有可能为 (f(fa,0)) 产生贡献,所以就不用管和不和环的根相连了。就是环的根一下的部分,能选出的最大独立集大小
    至于如何求,在 DP() 函数里用正反两遍 dp 解决

    其实这种仙人掌转圆方树的题似乎都是这个套路,就是转完圆方树以后,圆点的转移一般比较简单,而方点的可能还需要个 dp 啥的
    比如这个题也是这样,只不过有些难我没写出来,dp 不好啥都玩蛋啊https://www.luogu.com.cn/problem/P4244

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<map>
    #include<iomanip>
    #include<cstring>
    #define reg register
    #define EN puts("")
    inline int read(){
    	register int x=0;register int y=1;
    	register char c=std::getchar();
    	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
    	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
    	return y?x:-x;
    }
    #define N 100006
    #define M 300006
    struct graph{
    	int fir[N],nex[M],to[M],tot;
    	inline void add(int u,int v){
    		to[++tot]=v;
    		nex[tot]=fir[u];fir[u]=tot;
    	}
    }G,T;
    int n,m,bcccnt;
    int dfn[N],low[N],dfscnt;
    int stack[N],top;
    void tarjan(reg int u,int fa){
    	dfn[u]=low[u]=++dfscnt;stack[top++]=u;
    	for(reg int v,i=G.fir[u];i;i=G.nex[i]){
    		v=G.to[i];
    		if(v==fa) continue;
    		if(!dfn[v]){
    			tarjan(v,u);
    			low[u]=std::min(low[u],low[v]);
    			if(low[v]>dfn[u]) T.add(u,v);
    		}
    		else if(low[u]>dfn[v]){
    			low[u]=dfn[v];bcccnt++;
    			T.add(v,bcccnt);
    			for(reg int j=top-1;stack[j]^v;j--)	T.add(bcccnt,stack[j]);
    		}
    	}
    	top--;
    }
    int tmp[N];
    int f[N][2],dp[N][2];
    inline void DP(reg int u){
    	tmp[0]=0;
    	for(reg int i=T.fir[u];i;i=T.nex[i]) tmp[++tmp[0]]=T.to[i];
    	if(tmp[0]==2){
    		int son1=tmp[1],son2=tmp[2];
    		f[u][0]=f[son1][0]+f[son2][0];//son1 son2 都不能选
    		f[u][1]=std::max(f[son1][0]+f[son2][0],std::max(f[son1][0]+f[son2][1],f[son1][1]+f[son2][0]));
    		return;
    	}
    	dp[1][0]=f[tmp[1]][0];dp[1][1]=0;//第一个不能选,所以是 0
    	for(reg int v,i=2;i<=tmp[0];i++){
    		v=tmp[i];
    		dp[i][0]=std::max(dp[i-1][0],dp[i-1][1])+f[v][0];
    		dp[i][1]=dp[i-1][0]+f[v][1];
    	}
    	f[u][0]=dp[tmp[0]][0];f[u][1]=dp[tmp[0]][0];
    	dp[tmp[0]+1][0]=dp[tmp[0]+1][1]=0;
    	for(reg int v,i=tmp[0];i;i--){
    		v=tmp[i];
    		dp[i][0]=std::max(dp[i+1][0],dp[i+1][1])+f[v][0];
    		dp[i][1]=dp[i+1][0]+f[v][1];
    	}
    	f[u][1]=std::max(f[u][1],std::max(dp[1][0],dp[1][1]));
    }
    void dfs(int u){
    	f[u][1]=1;
    	for(reg int v,i=T.fir[u];i;i=T.nex[i]){
    		v=T.to[i];
    		dfs(v);
    		if(u<=n){
    			f[u][0]+=std::max(f[v][1],f[v][0]);f[u][1]+=f[v][0];
    		}
    	}
    	if(u>n) DP(u);
    }
    inline void debug_tarjan(){
    	puts("finished tarjan");
    	printf("bcccnt=%d
    ",bcccnt);
    	for(reg int i=1;i<=bcccnt;i++){
    		printf("i=%d
    ",i);
    		for(reg int j=T.fir[i];j;j=T.nex[j]) printf("%d ",T.to[j]);
    		puts("");
    	}
    }
    int main(){
    	n=read();m=read();
    	for(reg int u,v,i=1;i<=m;i++){
    		u=read();v=read();
    		G.add(u,v);G.add(v,u);
    	}
    	bcccnt=n;
    	tarjan(1,1);
    //		debug_tarjan();
    	dfs(1);
    	printf("%d",std::max(f[1][0],f[1][1]));
    	return 0;
    }
    
  • 相关阅读:
    springmvc结合freemarker,非自定义标签
    springmvc的ModelAndView的简单使用
    tomcat无法正常启动的一个原因
    通过springmvc的RequestMapping的headers属性的使用
    springmvc入门demo
    Redis的入门Demo(java)
    Ubuntu18.0.4查看显示器型号
    APS审核经验+审核资料汇总——计算机科学与技术专业上海德语审核
    Java连接GBase并封装增删改查
    SpringMVC源码阅读:异常解析器
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/13766086.html
Copyright © 2011-2022 走看看