码迷,mamicode.com
首页 > 其他好文 > 详细

环套树

时间:2015-08-26 17:23:22      阅读:417      评论:0      收藏:0      [点我收藏+]

标签:

bzoj1040 骑士

题目大意:给出每个骑士的攻击力和痛恨的人,每个骑士不能和自己痛恨的人一起出现,选一些骑士使得他们的攻击力最大。

思路:因为每个骑士恨一个人,所以是一个环套树森林(注意n点n边的联通图可能是环套树森林!!!),虽然题目是单向边,但等同于双向边。对于环套树dp的做法,可以搜到环后,把环从一处断开,对于这道题目,对断开后的两点分别为根做树型dp(要求根不能选),加给答案。但是要注意二元环的情况,我们可以对于二元环只加一次无向边(其实是两条有向边),因为二元环完全可以当作有边相连的两点处理,这个时候可能会出现一棵没有环的树,我们需要在退回到dfs起点的那个点的时候人为的做一下dp。

一定要十分注意二元环的情况!!!

技术分享
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define maxnode 1000005
using namespace std;
int point[maxnode]={0},next[maxnode*2]={0},en[maxnode*2]={0},tot=0,x=0,y=0,ai[maxnode]={0};
LL val[maxnode]={0},f[maxnode][2]={0},ans=0;
bool visit[maxnode]={false},ff;
void add(int u,int v)
{
    ++tot;next[tot]=point[u];point[u]=tot;en[tot]=v;
    ++tot;next[tot]=point[v];point[v]=tot;en[tot]=u;
}
void dp(int u,int fa)
{
    int i,j;
    f[u][1]=val[u];visit[u]=true;
    for (i=point[u];i;i=next[i])
    {
        if (en[i]!=fa)
        {
            if ((u==y&&en[i]==x)||(u==x&&en[i]==y)) continue;
            dp(en[i],u);
            f[u][0]+=max(f[en[i]][0],f[en[i]][1]);
            f[u][1]+=f[en[i]][0];
        }
    }
}
void dfs(int u,int fa)
{
    int i,j;LL ci=0;
    visit[u]=true;
    for (i=point[u];i;i=next[i])
    {
        if (en[i]!=fa)
        {
            if (visit[en[i]])
            {
                x=u;y=en[i];
                memset(f,0,sizeof(f));
                dp(x,y);ci=max(ci,f[x][0]);
                memset(f,0,sizeof(f));
                swap(x,y);dp(x,y);ci=max(ci,f[x][0]);
                ans+=ci;ff=true;return;
            }
            else
            {
               dfs(en[i],u);if (ff) return;
            }
        }
    }
    if (fa==0)
    {
        x=y=0;dp(u,0);
        ans+=max(f[u][0],f[u][1]);
    }
}
int main()
{
    int n,i,j;
    scanf("%d",&n);
    for (i=1;i<=n;++i) scanf("%I64d%d",&val[i],&ai[i]);
    for (i=1;i<=n;++i)
        if (ai[ai[i]]!=i||ai[i]>i) add(i,ai[i]);
    for (i=1;i<=n;++i)
      if (!visit[i]){ff=false;dfs(i,0);}
    printf("%I64d\n",ans);
}
View Code

 

环套树

标签:

原文地址:http://www.cnblogs.com/Rivendell/p/4760952.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!