zoukankan      html  css  js  c++  java
  • [bzoj] 1040 骑士 || 基环外向树dp

    原题

    给出n个点n条边和每个点的点权,一条边的两个断点不能同时选择,问最大可以选多少。


    //图是一张基环外向树森林
    是不是很像舞会啊~
    就是多了一条边。
    所以我们考虑一下对于一棵基环外向树,拆掉一条在环上的边,变成一棵树。在这个树上以断边的一个断点为根,跑舞会,就得到了这棵树的最大值(根选和根不选了两种)。考虑到对于拆下来的内一条边,也要满足断点不能同时选择,所以此时得到的答案中,根不选一定是正确的,但是根选不一定是正确的(因为我们不知道此刻另一个断点是否被选择)。
    那么我们强制该点不选,然后更新至根选的状态即可。

    #include<cstdio>
    #include<algorithm>
    #define N 1000010
    typedef long long ll;
    using namespace std;
    int n,a[N],f[N],head[N],ecnt=1,cnt[N];
    ll dp[N][2],ans;
    bool vis[N];
    struct hhh
    {
        int to,next;
    }edge[N];
    
    int read()
    {
        int ans=0,fu=1;
        char j=getchar();
        for (;j<'0' || j>'9';j=getchar()) if (j=='-') fu=-1;
        for (;j>='0' && j<='9';j=getchar()) ans*=10,ans+=j-'0';
        return ans*fu;
    }
    
    void add(int u,int v)
    {
        edge[ecnt].to=v;
        edge[ecnt].next=head[u];
        head[u]=ecnt++;
    }
    
    void dfs(int x)//经典dp
    {
        vis[x]=1;
        dp[x][1]=a[x];
        for (int i=head[x];i;i=edge[i].next)
    	if (!vis[edge[i].to])
    	{
    	    dfs(edge[i].to);
    	    dp[x][0]+=max(dp[edge[i].to][0],dp[edge[i].to][1]);
    	    dp[x][1]+=dp[edge[i].to][0];
    	}
    }
    
    void DP(int x)
    {
        int root;
        for (root=x;cnt[root]!=x;root=f[root])
    	cnt[root]=x;
        dfs(root);
        x=f[root];//x为当前根,那么不在树上的那条边就是x和f[x]的边,所以强制f[x]不选
        dp[x][1]=dp[x][0];
        for (x=f[x];x!=root;x=f[x])
        {
    	dp[x][0]=0;dp[x][1]=a[x];
    	for (int i=head[x];i;i=edge[i].next)
    	{
    	    dp[x][0]+=max(dp[edge[i].to][0],dp[edge[i].to][1]);
    	    dp[x][1]+=dp[edge[i].to][0];
    	}
        }
        dp[root][1]=a[root];
        for (int i=head[root];i;i=edge[i].next)
    	dp[root][1]+=dp[edge[i].to][0];//强制根选,则+=儿子们都不选
        ans+=max(dp[root][0],dp[root][1]);//取当前基环外向树的最大值
    }
    
    int main()
    {
        n=read();
        for (int i=1;i<=n;i++)
    	a[i]=read(),f[i]=read(),add(f[i],i);
        for (int i=1;i<=n;i++)//基环外向树森林
    	if (!vis[i]) DP(i);
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    Python:异常(待续)
    Python:函数解释(面向过程)
    MicroK8s第一篇:
    k8s第一篇:
    VMware Workstation centos7 虚拟机桥接方式联网,获取动态IP
    使用Java Service Wrapper在Linux下配置Tomcat应用
    Log4j 2.0读取配置文件的方法
    SQL(横表和纵表)行列转换,PIVOT与UNPIVOT的区别和使用方法举例
    jar包读取配置文件
    Java Service Wrapper 发布Java程序或者jar包为Windows服务
  • 原文地址:https://www.cnblogs.com/mrha/p/8249673.html
Copyright © 2011-2022 走看看