• 【BZOJ4316】小C的独立集(仙人掌,动态规划)


    【BZOJ4316】小C的独立集(仙人掌,动态规划)

    题面

    BZOJ

    题解

    除了普通的动态规划以外,这题还可以用仙人掌的做法来做。
    这里没有必要把圆方树给建立出来
    (Tarjan)的本质其实就是一个构建(dfs)树的过程
    所以我们在(Tarjan)的过程中求解就行了
    我们设(f[i][0/1])表示当前节点为(i),选或不选的子树的最大独立集
    当一条边是树边的时候,转移和树上的转移相同。
    否则暂时不转移。
    当我们做完当前点,发现它是一个环的最顶端的时候,我们需要重新对于这个环计算一遍答案。
    我们需要明白一点:对于环上的节点,只与环有关,挂在环外面的子树可以直接计算在一起。

    现在考虑对于环如何重新计算答案
    从这个环的最底端开始往上跳,每次合并一次答案
    先考虑如何计算最顶端不选
    这样子最底端选或者不选是没有关系的。
    维护两个变量(f_0,f_1),表示当前点选或者不选的答案
    向上转移和树上的转移就是一样的了。
    把算出来的(f_0)直接加给顶点
    然后计算顶端选,
    那么最底下的那个点就一定不能选,直接令(f_1)初值为(-infty)就好了

    这样子做完就相当于把环给单独拎出来考虑,
    然后就变成了树上的(dp)

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define ll long long
    #define RG register
    #define MAX 55555
    inline int read()
    {
        RG int x=0,t=1;RG char ch=getchar();
        while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
        if(ch=='-')t=-1,ch=getchar();
        while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
        return x*t;
    }
    struct Line{int v,next;}e[MAX*3];
    int h[MAX],cnt=1;
    int n,m,fa[MAX],f[MAX][2],dfn[MAX],low[MAX],tim;
    inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
    void dp(int u,int y)
    {
    	int t0,t1,f0=0,f1=0;
    	for(int i=y;i!=u;i=fa[i])
    	{
    		t0=f0+f[i][0];t1=f1+f[i][1];
    		f0=max(t0,t1);f1=t0;
    	}
    	f[u][0]+=f0;
    	f0=0;f1=-1e9;
    	for(int i=y;i!=u;i=fa[i])
    	{
    		t0=f0+f[i][0];t1=f1+f[i][1];
    		f0=max(t0,t1);f1=t0;
    	}
    	f[u][1]+=f1;
    }
    void dfs(int u,int ff)
    {
    	fa[u]=ff;dfn[u]=low[u]=++tim;
    	f[u][1]=1;f[u][0]=0;
    	for(int i=h[u];i;i=e[i].next)
    	{
    		int v=e[i].v;
    		if(!dfn[v])dfs(v,u),low[u]=min(low[u],low[v]);
    		else if(v!=ff)low[u]=min(low[u],dfn[v]);
    		if(low[v]>dfn[u])
    			f[u][1]+=f[v][0],f[u][0]+=max(f[v][0],f[v][1]);
    	}
    	for(int i=h[u];i;i=e[i].next)
    		if(fa[e[i].v]!=u&&dfn[u]<dfn[e[i].v])
    			dp(u,e[i].v);
    }
    int main()
    {
    	n=read();m=read();
    	for(int i=1;i<=m;++i)
    	{
    		int u=read(),v=read();
    		Add(u,v);Add(v,u);
    	}
    	dfs(1,0);
    	printf("%d
    ",max(f[1][0],f[1][1]));
    	return 0;
    }
    
    
  • 相关阅读:
    关于trunk、access以及hybrid的一些简单知识
    EasyUI 创建对话框
    EasyUI Window和Layout
    EasyUI 异步Tree
    EasyUI 创建Tree
    EasyUI Tree添加节点
    EasyUI Ajax 表单
    EasyUI Tree checkbox node
    EasyUI 表单 tree
    EasyUI DataGrid合并单元
  • 原文地址:https://www.cnblogs.com/cjyyb/p/9090499.html
Copyright © 2020-2023  润新知