zoukankan      html  css  js  c++  java
  • ZJOI2009 骑士

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


    看似是树形DP,但是实际上就是树形DP

    这道题是有环的,是一个基环树森林,每次DP的时候,把环上任意一条边删去,然后从和调边连接的两个点分别DP,要保证其中一个不选

    然后取更优值,累加到答案中

    判断环可以用并查集,然后DFS过程中连边

    下面给出代码:

    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<string>
    #define max(a,b) a > b ? a : b
    using namespace std;
    inline long long rd(){
        long long x=0,f=1;
        char ch=getchar();
        for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
        for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
        return x*f;
    }
    inline void write(long long x){
        if(x<0) putchar('-'),x=-x;
        if(x>9) write(x/10);
        putchar(x%10+'0');
        return ;
    }
    long long n;
    long long head[2000006];
    long long to[2000006];
    long long nxt[2000006];
    long long total=0;
    long long v[2000006],x[2000006];
    long long dp[1000006][2];
    void add(long long x,long long y){
        total++;
        to[total]=y;
        nxt[total]=head[x];
        head[x]=total;
        return ;
    }
    long long f[1000006];
    long long getf(long long v){
        if(f[v]==v) return v;
        return f[v]=getf(f[v]);
    }
    long long merge(long long x,long long y){
        if(getf(x)==getf(y)) return 1;
        f[getf(x)]=getf(y);
        return 0;
    }
    long long root1=0,root2=0;
    long long head2[2000006],to2[2000006];
    long long nxt2[2000006];
    long long total2=0;
    void solve(long long x,long long fa){
        dp[x][0]=0;dp[x][1]=v[x];
        for(long long e=head2[x];e;e=nxt2[e]){
            if(to2[e]!=fa){
                solve(to2[e],x);
                dp[x][1]+=dp[to2[e]][0];
                dp[x][0]+=max(dp[to2[e]][0],dp[to2[e]][1]);
            }
        }
        return ;
    }
    long long book[1000006];
    long long ff=0;
    void add2(long long x,long long y){
        total2++;
        to2[total2]=y;
        nxt2[total2]=head2[x];
        head2[x]=total2;
        return ;
    }
    void dfs(long long x,long long fa){
        book[x]=1;
        for(long long e=head[x];e;e=nxt[e]){
            if(to[e]!=fa){
                if(merge(x,to[e])){
                    ff=1;
                    root1=x;
                    root2=to[e];
                }
                else add2(x,to[e]),add2(to[e],x);
                if(book[to[e]]==0) dfs(to[e],x);
            }
        }
        return ;
    }
    int main(){
        long long ans=0;
        n=rd();
        for(long long i=1;i<=n;i++) f[i]=i;
        for(long long i=1;i<=n;i++){
            v[i]=rd(),x[i]=rd();
            add(x[i],i),add(i,x[i]);
        }
        for(long long i=1;i<=n;i++){
            if(!book[i]){
                ff=0;
                dfs(i,0);
                if(!ff){
                    solve(i,0);
                    ans+=max(dp[i][0],dp[i][1]);
                }
                else{
                    solve(root1,0);
                    long long set=dp[root1][0];
                    solve(root2,0);
                    ans+=max(set,dp[root2][0]);
                }
            }
        }
        write(ans);
        return 0;
    }

    (20行版本):

    #include<algorithm>
    #include<cstdio>
    #include<string>
    #define max(a,b) a > b ? a : b
    using namespace std;
    inline long long rd(){long long x=0,f=1; char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; return x*f;}
    inline void write(long long x){if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0');}
    long long n,head[2000006],to[2000006],nxt[2000006],total=0,v[2000006],x[2000006],dp[1000006][2],f[1000006];
    void add(long long x,long long y){total++;to[total]=y;nxt[total]=head[x];head[x]=total;}
    long long getf(long long v){return (f[v]==v)?v:f[v]=getf(f[v]);}
    long long merge(long long x,long long y){if(getf(x)==getf(y)) return 1;else f[getf(x)]=getf(y); return 0;}
    long long root1=0,root2=0,head2[2000006],to2[2000006],nxt2[2000006],total2=0,book[1000006],ff=0;
    void solve(long long x,long long fa){dp[x][0]=0;dp[x][1]=v[x];for(long long e=head2[x];e;e=nxt2[e]) if(to2[e]!=fa){solve(to2[e],x);dp[x][1]+=dp[to2[e]][0];dp[x][0]+=max(dp[to2[e]][0],dp[to2[e]][1]);}return ;}
    void add2(long long x,long long y){total2++;to2[total2]=y;nxt2[total2]=head2[x];head2[x]=total2;}
    void dfs(long long x,long long fa){book[x]=1;for(long long e=head[x];e;e=nxt[e]) if(to[e]!=fa){if(merge(x,to[e])) ff=1,root1=x,root2=to[e];else add2(x,to[e]),add2(to[e],x);if(book[to[e]]==0) dfs(to[e],x);}return ;}
    int main(){
        long long ans=0,set=0;n=rd(); for(long long i=1;i<=n;i++) f[i]=i; for(long long i=1;i<=n;i++){v[i]=rd(),x[i]=rd();add(x[i],i),add(i,x[i]);}
        for(long long i=1;i<=n;i++) if(!book[i]){ff=0;dfs(i,0);if(!ff){solve(i,0);ans+=max(dp[i][0],dp[i][1]);continue;}solve(root1,0);set=dp[root1][0];solve(root2,0);ans+=max(set,dp[root2][0]);}write(ans);
        return 0;
    }
  • 相关阅读:
    最常用的CountDownLatch, CyclicBarrier你知道多少? (Java工程师必会)
    浅谈Java中的Condition条件队列,手摸手带你实现一个阻塞队列!
    实习到公司倒闭,2019我的技术踩坑之路!
    Java中的等待唤醒机制—至少50%的工程师还没掌握!
    告别编码5分钟,命名2小时!史上最全的Java命名规范参考!
    解决SELinux阻止Nginx访问服务
    ZooKeeper使用入门
    JVM致命错误日志详解
    虚拟机中设置 CentOS 静态 IP
    Spring 核心技术(7)
  • 原文地址:https://www.cnblogs.com/WWHHTT/p/10060390.html
Copyright © 2011-2022 走看看