zoukankan      html  css  js  c++  java
  • bzoj1040: [ZJOI2008]骑士

    1040: [ZJOI2008]骑士

    Time Limit: 10 Sec  Memory Limit: 162 MB

    Description

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

    Input

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

    Output

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

    Sample Input

    3
    10 2
    20 3
    30 1

    Sample Output

    30

    HINT

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

    Source

    首先想到将互相矛盾的两名骑士之间连边,若图中没有环,那么就是“没有上司的舞会”模板题(建议先做这个);

    因为每名骑士只有一个与他矛盾的士兵,也就是说一个点只有一条出边,那么我们可以证明一个联通块中至多只会出现一个环(证明略);

    有环该怎么做呢?取一条环上的任意一条边(为什么?请读者自行思考(o(╥﹏╥)o其实是我不会)),将其删去,对删去的边的两个端点分别为根进行一次dp(dp时根节点不取到);

    判环可以用DFS;

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<algorithm>
     5 #define MAXN 2000008
     6 using namespace std;
     7  
     8 int n,m,tot,cnt,fa[MAXN],head[MAXN],next[MAXN],vet[MAXN],a[MAXN],q[MAXN][2];
     9 long long ans,res,dp[MAXN][2];
    10  
    11 inline int read(){
    12     char ch=getchar(); int f=1,x=0;
    13     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    14     while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
    15     return x*f;
    16 }
    17  
    18 void add(int x,int y){
    19     tot++;
    20     next[tot]=head[x];
    21     head[x]=tot;
    22     vet[tot]=y;
    23 }
    24  
    25 int find(int x){
    26     if(fa[x]==x) return x;
    27     return fa[x]=find(fa[x]);
    28 }
    29  
    30 void merge(int aa,int bb){
    31     int ii=find(aa);
    32     int jj=find(bb);
    33     if(ii!=jj){
    34         add(aa,bb);
    35         add(bb,aa);
    36         fa[jj]=ii;
    37     }
    38     else{
    39         q[++cnt][0]=aa;
    40         q[cnt][1]=bb;
    41     }
    42          
    43 }
    44  
    45 void dfs(int u,int fa){
    46     dp[u][1]=0; dp[u][0]=0;
    47     for(int i=head[u];i;i=next[i]){
    48         int y=vet[i];
    49         if(y==fa) continue;
    50         dfs(y,u);
    51         dp[u][0]+=max(dp[y][1],dp[y][0]);
    52         dp[u][1]+=dp[y][0];
    53     }
    54     dp[u][1]+=a[u];
    55 }
    56  
    57 int main(){
    58     n=read(); cnt=0; tot=0;
    59     for(int i=1;i<=n;i++) fa[i]=i;
    60     for(int i=1;i<=n;i++){
    61         int x;
    62         a[i]=read(); x=read();
    63         merge(i,x);
    64     }
    65     ans=0; res=0;
    66     for(int i=1;i<=cnt;i++){
    67         int x=q[i][0],y=q[i][1];
    68         dfs(x,-1); res=dp[x][0];
    69         dfs(y,-1); ans+=max(res,dp[y][0]);
    70     }
    71     printf("%lld",ans);
    72 }
  • 相关阅读:
    [DB] 数据库的连接
    JS leetcode 翻转字符串里的单词 题解分析
    JS leetcode 拥有最多糖果的孩子 题解分析,六一快乐。
    JS leetcode 搜索插入位置 题解分析
    JS leetcode 杨辉三角Ⅱ 题解分析
    JS leetcode 寻找数组的中心索引 题解分析
    JS leetcode 移除元素 题解分析
    JS leetcode 最大连续1的个数 题解分析
    JS leetcode 两数之和 II
    JS leetcode 反转字符串 题解分析
  • 原文地址:https://www.cnblogs.com/WQHui/p/8570125.html
Copyright © 2011-2022 走看看