• 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 }
  • 相关阅读:
    T100——MENU按钮
    vue 打包问题
    Python: 什么是*args和**kwargs
    windows服务器下部署Apache+Flask+Mod_wsgi+Vue
    树莓派 端口被占用的解决方案
    mac 终端命令总结
    Home Assistant 发现小米设备
    树莓派基于Home Assistant 查询在网设备
    Linux 命令集合-vim
    mac上的hassbian 启动报错1
  • 原文地址:https://www.cnblogs.com/WQHui/p/8570125.html
Copyright © 2020-2023  润新知