首页 > 其他 > 详细

zoj 3527 Shinryaku! Kero Musume (树形dp---带尾巴的环的处理)

时间:2014-02-17 11:54:26      阅读:456      评论:0      收藏:0      [点我收藏+]

题意:n个点,每个点有一个faith值,然后有一个关联的点。如果在i点和它的关联点pi同时修

神庙则得到的faith值变为fi+gi,如果只在i点修不在pi修建,则得到的faith值为fi。问最优修建方案

中能获得的faith值即求能获得的最大faith值。


算法:

由于有n个点和n条边,所以一定是一个带环的图,环外有小尾巴。

对于环外的点,利用dp[i][0]+=max(dp[soni][0],dp[soni][1])和dp[i][1]+=max(dp[soni][0],dp[soni][1]+g[son])

不断向上缩点。

对于每个环,则枚举其中一个点的状态,之后就成了一条链,又可以运用上面的方程。


这个选与不选问题的dp方程是树形dp里比较基本的类型。如poj 2342 Anniversary party

  POJ 1463 && HDU 1054 Strategic Game


这题比较新颖在于图中环的处理,枚举环中一个点来使环变为链。


我没想出这个枚举的方法,参考了下面的blog。

http://blog.csdn.net/ahero_happy/article/details/6728471


#include<cstdio>
#include<iostream>
#include<cstring>
#define ll long long
#define maxn 100010

using namespace std;

int in[maxn],q[maxn],p[maxn],f[maxn],g[maxn];
ll dp[maxn][2],dp1[maxn][2];
bool vis[maxn];

ll maxx(ll a,ll b)
{
    return a>b?a:b;
}

ll dfs1(int st,int cur,ll dp[][2],int flag)
{
    int k=cur;
    int i=p[k];
    while(i!=st)
    {
        dp[i][0]+=maxx(dp[k][0],dp[k][1]);
        dp[i][1]+=maxx(dp[k][0],dp[k][1]+g[k]);
        k=i;
        i=p[k];
    }
    if(flag) dp[k][1]+=g[k];
    return  maxx(dp[k][0],dp[k][1]);
}

ll dfs(int now)
{
    int k=now;
    int i=p[k];
    dp1[i][0]+=dp[k][0];
    dp1[i][1]+=dp[k][0];//now不取
    ll a1=dfs1(k,i,dp1,0);

    dp[i][0]+=dp[k][1];
    dp[i][1]+=dp[k][1]+g[k];//now取
    ll a2=dfs1(k,i,dp,1);

    return maxx(a1,a2);
}

int main()
{
    int n,rear;
    ll sum;
    while(scanf("%d",&n)!=EOF)
    {
        memset(in,0,sizeof(in));
        memset(vis,0,sizeof(vis));
        memset(dp,0,sizeof(dp));

        for(int i=1;i<=n;i++)
        {
            scanf("%d%d%d",&f[i],&g[i],&p[i]);
            in[p[i]]++;
        }
        rear=0;
        for(int i=1;i<=n;i++)
        {
            dp[i][1]=f[i];
            if(!in[i])
                q[rear++]=i;
        }
        while(rear)
        {
            int k = q[--rear];
            vis[k] = true;
            int i = p[k];
            dp[i][0]+=maxx(dp[k][0],dp[k][1]);
            dp[i][1]+=maxx(dp[k][0],dp[k][1]+g[k]);
            if((--in[i])==0)
                q[rear++]=i;
        }
        memcpy(dp1,dp,sizeof(dp));
        sum=0;
        for(int i=1;i<=n;i++)
        {
            if(!vis[i])
            {
                sum+=dfs(i);
                vis[i]=true;
                for(int j=p[i];j!=i;j=p[j])
                    vis[j]=true;
            }
        }
        printf("%lld\n",sum);
    }
    return 0;
}



zoj 3527 Shinryaku! Kero Musume (树形dp---带尾巴的环的处理)

原文:http://blog.csdn.net/u012841845/article/details/19292505

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!