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

摘要:
Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英。他们劫富济贫,惩恶扬善,受到社会各界的赞扬。最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争。战火绵延,人民生灵涂炭,组织起一个骑士军团加入战斗刻不容缓!Output应包含一行,包含一个整数,表示你所选出的骑士军团的战斗力。SampleInput3102203301SampleOutput30HintN≤1000000,每名骑士的战斗力都是不大于1000000的正整数。

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

Input

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

Output

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

Sample Input3 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 namespacestd;

const int maxn=1000000;

int fight[maxn+5];

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

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

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

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

void dfs1(int x,intfa)
{
    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(intx)
{
    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];
}

intmain()
{
    intn;
    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
",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
",temp,dp[en][0]);
                    ans+=max(temp,dp[en][0]);
                }
            }
        }

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

免责声明:文章转载自《HYSBZ 1040 骑士 (基环外向树DP)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇机器学习基础:(Python)训练集测试集分割与交叉验证pytorch 基础内容下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

bzoj:1072: [SCOI2007]排列perm

Description   给一个数字串s和正整数d, 统计s有多少种不同的排列能被d整除(可以有前导0)。例如123434有90种排列能被2整除,其中末位为2的有30种,末位为4的有60种。 Input   输入第一行是一个整数T,表示测试数据的个数,以下每行一组s和d,中间用空格隔开。s保证只包含数字0, 1, 2, 3, 4, 5, 6, 7, 8,...

AcWing 2879. 画中漂流(简单DP)

在梦境中,你踏上了一只木筏,在江上漂流。 根据对当地的了解,你知道在你下游 D 米处有一个峡谷,如果你向下游前进大于等于 D 米则必死无疑。 现在你打响了急救电话,T 秒后救援队会到达并将你救上岸。 水流速度是 1 米/秒,你现在有 M 点体力。 每消耗一点体力,你可以划一秒桨使船向上游前进 1 米,否则会向下游前进 1 米(水流)。 M 点体力需在救援队...

POJ 2411 Mondriaan's Dream -- 状压DP

题目:Mondriaan's Dream 链接:http://poj.org/problem?id=2411 题意:用 1*2 的瓷砖去填 n*m 的地板,问有多少种填法。 思路:   很久很久以前便做过的一道题目,状压DP,当时写得估计挺艰辛的,今天搜插头DP又搜到它,就先用状压DP写了下,顺利多了,没一会就出来了,可惜因为long long没有1A。...

【DP】洛谷 P1854 花店橱窗布置

你们好啊,我又回来了。P1854这是一道动态规划题。 还是先放题目,防止走错》》》 这次先放数据,上次就忘了.......... 其实我们看见数据只有100,其实就可以考虑瞎搞,什么记忆化搜索,题解还有人求最长路,闲的无聊你可以自己尝试。 我这里介绍一下这题正解 -> dp。 其实很显然的吧........ 这个题,我们考虑我们考虑用f[i][j...

题目:[NOIP1999]拦截导弹(最长非递增子序列DP) O(n^2)和O(n*log(n))的两种做法

题目:[NOIP1999]拦截导弹 问题编号:217 题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。 输入格式 输入数据为两...

Rabbit的工作(1) (dP)

题目:题目链接 一个人工作时越工作越累,连续工作k天每天消耗体力为k,并且他最多消耗m的体力,当他休息一天后就可以恢复所有体力。在公司工作,给出一个字符01串,s[i]=0时表示第i天公司放假,他休息。s[i]=1时他可以自由选择休息还是工作。问这个人最多工作多少天? dp题。用dp[i][j][k]表示前i天工作j天且最近连续工作k天的最小花费。s[...