HYSBZ 1040 骑士 (基环外向树DP)

Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英。他们劫富济贫,惩恶扬善,受到社会各
界的赞扬。最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争。战火绵延五百里,在和平环境
中安逸了数百年的Z国又怎能抵挡的住Y国的军队。于是人们把所有的希望都寄托在了骑士团的身上,就像期待有一
个真龙天子的降生,带领正义打败邪恶。骑士团是肯定具有打败邪恶势力的能力的,但是骑士们互相之间往往有一
些矛盾。每个骑士都有且仅有一个自己最厌恶的骑士(当然不是他自己),他是绝对不会与自己最厌恶的人一同出
征的。战火绵延,人民生灵涂炭,组织起一个骑士军团加入战斗刻不容缓!国王交给了你一个艰巨的任务,从所有
的骑士中选出一个骑士军团,使得军团内没有矛盾的两人(不存在一个骑士与他最痛恨的人一同被选入骑士军团的
情况),并且,使得这支骑士军团最具有战斗力。为了描述战斗力,我们将骑士按照1至N编号,给每名骑士一个战
斗力的估计,一个军团的战斗力为所有骑士的战斗力总和。

Input

  第一行包含一个正整数N,描述骑士团的人数。接下来N行,每行两个正整数,按顺序描述每一名骑士的战斗力
和他最痛恨的骑士。

Output

  应包含一行,包含一个整数,表示你所选出的骑士军团的战斗力。

Sample Input 3 10 2 20 3 30 1

Sample Output30Hint

N ≤ 1 000 000,每名骑士的战斗力都是不大于 1 000 000的正整数。

题目大意:

分别给你n个骑士的战斗力和他痛恨的骑士(有且仅有一个且不是自己)。要你组织一个军团,使得军团战斗力最强,且军团中没有一个人是另一个人所痛恨的。军团战斗力极为骑士战斗力之和。

看到题目,就想到了之前做到的摘苹果问题(没有上司的聚会)。相邻等级的苹果不能同时被采摘。

DP表达式即为:dp[i][0]=∑max(dp[son][0],dp[son][1]);dp[i][1]=∑dp[son][0];

但是这道题是可能出现环(环上至少有3个元素)的。

如果出现环,则删去环中的一条边,从这条边的两点分别做DP,最后答案便是max(dp[st][0],dp[en][0]),即两点不可能同时取到。

此题可能有多个连通分量,且并非所有连通分量都一定有环(有互相痛恨的骑士)(这导致一条无向边可能存储了两次,要删去一个),这些在代码中都要注意。

答案要lol,链式前向星要开双倍数组!

#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>

using namespace std;

const int maxn=1000000;

int fight[maxn+5];

int to[maxn*2+5];
int nex[maxn*2+5];
int head[maxn+5];
int cnt;

void addedge(int u,int v)
{
    to[cnt]=v;
    nex[cnt]=head[u];
    head[u]=cnt++;
}

bool isedge(int u,int v)
{
    for(int i=head[u];i!=-1;i=nex[i])
    {
        if(to[i]==v)
            return true;
    }
    return false;
}

int vis1[maxn+5];
int st,en;

void dfs1(int x,int fa)
{
    vis1[x]=1;
    for(int i=head[x];i!=-1;i=nex[i])
    {
        if(to[i]!=fa)
        {
            if(!vis1[to[i]])
                dfs1(to[i],x);
            else
            {
                st=x;
                en=to[i];
            }
        }
    }
}

long long dp[maxn+5][2];
int vis2[maxn+5];

void dfs2(int x)
{
    vis2[x]=1;
    bool flag=false;
    for(int i=head[x];i!=-1;i=nex[i])
    {
        if(!vis2[to[i]]&&!((x==st&&to[i]==en)||(x==en&&to[i]==st)))
        {
            dfs2(to[i]);
            flag=true;
            dp[x][1]+=dp[to[i]][0];
            dp[x][0]+=max(dp[to[i]][0],dp[to[i]][1]);
        }
    }
    dp[x][1]+=1LL*fight[x];
    if(!flag)
        dp[x][1]=1LL*fight[x];
}

int main()
{
    int n;
    while(scanf("%d",&n)!=EOF)
    {
        memset(head,-1,sizeof(head));
        cnt=0;
        for(int i=1,a,b;i<=n;i++)
        {
            scanf("%d%d",&a,&b);
            fight[i]=a;
            if(!isedge(i,b))
            {
                addedge(i,b);
                addedge(b,i);
            }
        }

        long long ans=0;
        memset(vis1,0,sizeof(vis1));
        for(int i=1;i<=n;i++)
        {
            if(!vis1[i])
            {
                st=-1,en=-1;
                dfs1(i,-1);
                //printf("%d %d\n",st,en);
                if(st==-1&&en==-1)
                {
                    memset(vis2,0,sizeof(vis2));
                    memset(dp,0,sizeof(dp));
                    dfs2(i);
                    ans+=max(dp[i][0],dp[i][1]);
                }
                else
                {
                    memset(vis2,0,sizeof(vis2));
                    memset(dp,0,sizeof(dp));
                    dfs2(st);
                    long long temp=dp[st][0];
                    memset(vis2,0,sizeof(vis2));
                    memset(dp,0,sizeof(dp));
                    dfs2(en);
                    //printf("%d %d\n",temp,dp[en][0]);
                    ans+=max(temp,dp[en][0]);
                }
            }
        }

        printf("%lld\n",ans);
    }
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/acboyty/p/9784918.html