zoukankan      html  css  js  c++  java
  • [BZOJ 1040] 骑士

    Link:

    BZOJ 1040 传送门

    Solution:

    基环树$dp$

    如果仅仅是一棵树,直接树形$dp$即可,维护选与不选两种状态下的方案数

    但此题是一个基环树,即除了一个环外是一个树形结构

    对于环,一般都是将环转化为链处理

    我们只需要删掉环上的任意一条边即可将环转化为树,那我们只需要人为判断这条边对答案的贡献就行了

    设这条边是$(u,v)$,那么有2种情况

    1.不选$u$,那么$v$选不选都行,以$u$为根跑一遍树形$dp$

    2.不选$v$,那么$u$选不选都行,以$v$为根跑一遍树形$dp$

    建图有两种方式:

    Solution A:

    先将原图建好,$dfs$找到返祖边,删除返祖边

    Solution B:

    在连边时用并查集维护,如果出现环则不连这条边

    Solution B 跑得更快些

    Code:

    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    const int MAXN=1e6+10;
    
    bool vis[MAXN],flag=false;
    int n,l,r,dat[MAXN],mat[MAXN];
    ll dp[MAXN][2],res=0;
    vector<int> G[MAXN];
    
    void dfs(int x,int anc)
    {
        vis[x]=true;
        for(int i=0;i<G[x].size() && !flag;i++)
        {
            int v=G[x][i];
            if(v==anc) continue;
            if(vis[v]) 
            {
                flag=true;
                G[x].erase(find(G[x].begin(),G[x].end(),v));
                G[v].erase(find(G[v].begin(),G[v].end(),x));
                l=x;r=v;break;
            }
            dfs(v,x);
        }
    }
    
    void Trdp(int x,int anc,int ban)
    {
        vis[x]=true;
        if(x==ban) dp[x][1]=0;
        else dp[x][1]=dat[x];
        dp[x][0]=0;
        for(int i=0;i<G[x].size();i++)
        {
            int v=G[x][i];
            if(v==anc) continue;
            Trdp(v,x,ban);
            dp[x][0]+=max(dp[v][0],dp[v][1]);
            dp[x][1]+=dp[v][0];
        }
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&dat[i],&mat[i]);
            G[i].push_back(mat[i]);G[mat[i]].push_back(i);
        }
        for(int i=1;i<=n;i++)
        {
            if(vis[i]) continue;
            ll t=0;flag=false;dfs(i,0);
            Trdp(l,0,r);t=max(dp[l][0],dp[l][1]);
            Trdp(r,0,l);t=max(t,max(dp[r][0],dp[r][1]));
            res+=t;
        }
        printf("%lld",res);
        return 0;
    }
    Solution A
    #include <bits/stdc++.h>
    
    using namespace std;
    typedef long long ll;
    const int MAXN=1e6+10;
    
    vector<int> G[MAXN];
    ll dp[MAXN][2],res=0,t=0;
    int f[MAXN],n,x,dat[MAXN],l[MAXN],r[MAXN],cnt=0;
    
    int find(int x){return (x==f[x])?x:(f[x]=find(f[x]));}
    void Trdp(int x,int anc)
    {
        dp[x][0]=0;dp[x][1]=dat[x];
        for(int i=0;i<G[x].size();i++)
        {
            int v=G[x][i];
            if(v==anc) continue;
            Trdp(v,x);
            dp[x][0]+=max(dp[v][1],dp[v][0]);
            dp[x][1]+=dp[v][0];
        }
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) f[i]=i;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&dat[i],&x);
            if(find(i)!=find(x))
            {
                G[x].push_back(i);G[i].push_back(x);
                f[f[i]]=f[x];
            }
            else l[++cnt]=i,r[cnt]=x;
        }
        for(int i=1;i<=cnt;i++)
        {
            Trdp(l[i],0);t=dp[l[i]][0];
            Trdp(r[i],0);t=max(t,dp[r[i]][0]);
            res+=t;
        }
        printf("%lld",res);
        return 0;
    }
    Solution B

    Review:

    1、处理环的常用方式:将环转化为链

    2、用并查集维护点集的方式寻找环的效率更高

  • 相关阅读:
    Lodash JS实用类库 数组操作 延时执行 功能强大
    7.【nuxt起步】-Nuxt与后端数据交互
    vue图片懒加载
    猎鹰与龙飞船基于 Linux,采用 C++、Chromium 与 JS 开发
    | 和 ||,& 和 && 的区别
    Linux安装.net core
    Linux下程序后台运行:nohup和&
    vuejs如何调试代码
    全局安装 Vue cli3 和 继续使用 Vue-cli2.x
    导入sass文件
  • 原文地址:https://www.cnblogs.com/newera/p/9248351.html
Copyright © 2011-2022 走看看