• LOJ10162 骑士


    ZJOI 2008

    Z 国的骑士团是一个很有势力的组织,帮会中聚集了来自各地的精英。他们劫富济贫,惩恶扬善,受到了社会各界的赞扬。

    可是,最近发生了一件很可怕的事情:邪恶的 Y 国发起了一场针对 Z 国的侵略战争。战火绵延五百里,在和平环境中安逸了数百年的 Z 国又怎能抵挡得住 Y 国的军队。于是人们把所有希望都寄托在了骑士团身上,就像期待有一个真龙天子的降生,带领正义打败邪恶。

    骑士团是肯定具备打败邪恶势力的能力的,但是骑士们互相之间往往有一些矛盾。每个骑士有且仅有一个他自己最厌恶的骑士(当然不是他自己),他是绝对不会与最厌恶的人一同出征的。

    战火绵延,人们生灵涂炭,组织起一个骑士军团加入战斗刻不容缓!国王交给你了一个艰巨的任务:从所有骑士中选出一个骑士军团,使得军内没有矛盾的两人,即不存在一个骑士与他最痛恨的人一同被选入骑士团的情况,并且使这支骑士军团最富有战斗力。

    为描述战斗力,我们将骑士按照 1 至 N 编号,给每位骑士估计一个战斗力,一个军团的战斗力为所有骑士的战斗力之和。

    输入格式

    输入第一行包含一个正整数 N,描述骑士团的人数;

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

    输出格式

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

    样例

    样例输入

    3
    10 2
    20 3
    30 1

    样例输出

    30

    数据范围与提示

    对于 30% 的数据,满足 N10;

    对于 60% 的数据,满足 N100;

    对于 80% 的数据,满足N10^4;

    对于 100% 的数据,满足 N10^6,且每名骑士的战斗力都是不大于 10^6 的正整数。

    _____________________________________________________________________________________________

    树形动归,n个点,n条边,那么整个图构成多个联通块,每个块内要么是一棵树,要么是一棵树加一条边构成一个环。

    如果是树,直接动归就可以了。

    f[u][0]:表示不选当前点的最大战力

    f[u][1]:表示选当前点的最大战力

    f[u][0]=sum( max( f[v][0],f[v][1] ) )

    f[u][1]=sum( f[v][0] )+zl[u];

    如果内部是一个树加边,那么环上断开一条边,边的两个端点u,v,他们不能同时取。所以只要求f[u][0]和f[v][0]的较大值就可以了。

    _____________________________________________________________________________________________

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef long long ll;
     4 const int maxn=1e6+10;
     5 int n;
     6 long long ans;
     7 ll zl[maxn];
     8 int hen[maxn];
     9 struct edge
    10 {
    11     int u,v,nxt;
    12 }e[maxn<<1];
    13 int head[maxn],js;
    14 void addage(int u,int v)
    15 {
    16     e[++js].u=u;e[js].v=v;
    17     e[js].nxt=head[u];head[u]=js;
    18 }
    19 bool vis[maxn];
    20 long long f[maxn][2];
    21 int h1,h2,bz=0,root;
    22 void dfs(int u,int fa)
    23 {
    24     if(vis[u]==0)
    25     {
    26         vis[u]=1;
    27     }
    28     else 
    29     {
    30         h1=u;h2=fa;bz=1;
    31         return;
    32     }
    33     for(int i=head[u];i;i=e[i].nxt)
    34     {
    35         int v=e[i].v;
    36         if(v!=fa)dfs(v,u);
    37     }
    38 }
    39 void dp(int u,int fa)
    40 {
    41     f[u][0]=0;
    42     f[u][1]=zl[u];
    43     for(int i=head[u];i;i=e[i].nxt)
    44     {
    45         int v=e[i].v;
    46         if(v!=fa && v!=root)
    47         {
    48             dp(v,u);
    49             f[u][0]+=max(f[v][0],f[v][1]);
    50             f[u][1]+=f[v][0];
    51         }
    52     }
    53 }
    54 int main()
    55 {
    56     scanf("%d",&n);
    57     for(int i=1;i<=n;++i)
    58     {
    59         scanf("%d%d",&zl[i],&hen[i]);
    60         if(hen[hen[i]]==i)continue;
    61         addage(i,hen[i]);
    62         addage(hen[i],i);
    63     }
    64     for(int i=1;i<=n;++i)
    65         if(!vis[i])
    66         {
    67             h1=h2=bz=0;
    68             dfs(i,0);
    69             if(bz==0)
    70             {
    71                 root = i;
    72                 dp(i,0);
    73                 ans+=max(f[i][0],f[i][1]);
    74             }
    75             else
    76             {
    77                 root=h1;dp(h1,h2);long long tp=f[h1][0];
    78                 root=h2;dp(h2,h1);
    79                 ans+=max(tp,f[h2][0]);
    80             }
    81         }
    82     cout<<ans;
    83     return 0;
    84 }
    View Code
  • 相关阅读:
    八十九:ECMAScript6扩展之字符串、for-of
    八十八:ECMAScript6之解构赋值
    八十七:ECMAScript6基础入门之let、const
    八十六:JavaScript之表单验证案例
    八十五:JavaScript之正则表达式之实现正则测试工具
    八十四:JavaScript之正则表达式之常用的正则表达式
    vim常用命令总结(转)
    Linux常用命令
    LinkedBlockingQueue的put,add跟offer的区别
    RabbitMQ消息确认(发送确认,接收确认)
  • 原文地址:https://www.cnblogs.com/gryzy/p/10179705.html
Copyright © 2020-2023  润新知