• bzoj 1040: [ZJOI2008]骑士 環套樹DP


    1040: [ZJOI2008]骑士

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 1755  Solved: 690
    [Submit][Status]

    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

    对于100%的测试数据,满足N ≤ 1 000 000,每名骑士的战斗力都是不大于   1 000 000的正整数。

    Source

       ╮(╯▽╰)╭ 網上說什麼外向樹內向樹,完全不懂,說白了,這道題就是一個環套樹DP,由於每個人只貢獻一條邊,所以最終圖的結構只會是一系列包含一個環的聯通快,在這些聯通塊上分別做環套樹DP就行了。

      這道題環套樹DP非常簡單,直接隨機選環上一條邊刪掉,然後特殊處理刪掉邊的兩個端點,使之不被選擇,然後在樹上DP即可。

      這是我第一次編環套樹。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<ctime>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<string>
    #include<queue>
    using namespace std;
    #ifdef WIN32
    #define LL "%I64d"
    #else
    #define LL "%lld"
    #endif
    #define MAXN 1100000
    #define MAXV MAXN*2
    #define MAXE MAXV*2
    #define INF 0x3f3f3f3f
    #define INFL 0x00003f3f3f3f3f3fLL
    typedef long long qword;
    inline int nextInt()
    {
            char ch;
            int x=0;
            bool flag=false;
            do
                    ch=getchar(),flag=(ch=='-')?true:flag;
            while(ch<'0'||ch>'9');
            do x=x*10+ch-'0';
            while (ch=getchar(),ch<='9' && ch>='0');
            return x*(flag?-1:1);
    }
    
    int n,m;
    int e[MAXN][3];
    struct Edge
    {
            int np;
            Edge *next;
    }E[MAXE],*V[MAXV];
    int tope=-1;
    void addedge(int x,int y)
    {
            E[++tope].np=y;
            E[tope].next=V[x];
            V[x]=&E[tope];
    }
    int uf[MAXN];
    int get_fa(int now)
    {
            return (now==uf[now])?now:(uf[now]=get_fa(uf[now]));
    }
    bool comb(int x,int y)
    {
            x=get_fa(x);
            y=get_fa(y);
            if (x==y)return false;
            uf[x]=y;
            return true;
    }
    int roof[MAXN],topr=-1;
    int state[MAXN];
    int ptr[MAXN];
    int v[MAXN];
    pair<qword,qword> dfs(int now,int f)
    {
            pair<qword,qword> ret,t;
            Edge *ne;
            ret=make_pair(v[now],0);
            for (ne=V[now];ne;ne=ne->next)
            {
                    if (ne->np==f)continue;
                    t=dfs(ne->np,now);
                    ret.second+=max(t.first,t.second);
                    ret.first+=t.second;
            }
            if (state[now])ret.first=-INFL;
            return ret;
    }
    int main()
    {        int i,j,k;
            int x,y,z;
            qword ans=0;
            scanf("%d",&n);
            memset(ptr,-1,sizeof(ptr));
            for (i=0;i<=n;i++)uf[i]=i;
            for (i=0;i<n;i++)
            {
                    scanf("%d%d",&v[i+1],&e[i][1]);
                    e[i][0]=i+1;
                    if (!comb(e[i][0],e[i][1]))
                    {
                            roof[++topr]=e[i][0];
                            e[i][2]=true;
                            ptr[e[i][0]]=e[i][1];
                    }else
                    {
                            addedge(e[i][0],e[i][1]);
                            addedge(e[i][1],e[i][0]);
                    }
            }
            for (i=0;i<=topr;i++)
            {
                    state[get_fa(roof[i])]=true;
            }
            for (i=1;i<=n;i++)
            {
                    if (!state[get_fa(i)])
                    {
                            state[get_fa(i)]=true;
                            roof[++topr]=get_fa(i);
                    }
            }
            memset(state,0,sizeof(state));
            pair<qword,qword> pr;
            qword t;
            for (i=0;i<=topr;i++)
            {
                    if (ptr[roof[i]]==-1)
                    {
                            pr=dfs(roof[i],roof[i]);
                            ans+=max(pr.first,pr.second);
                    }else
                    {
                            //state[roof[i]]=true;
                            state[ptr[roof[i]]]=true;
                            pr=dfs(roof[i],roof[i]);
                            t=max(pr.first,pr.second);
                            state[ptr[roof[i]]]=false;
                            pr=dfs(roof[i],roof[j]);
                            t=max(t,pr.second);
                            ans+=t;
                    }
            }
            printf(LL"
    ",ans);
            return 0;
    }
     
    by mhy12345(http://www.cnblogs.com/mhy12345/) 未经允许请勿转载

    本博客已停用,新博客地址:http://mhy12345.xyz

  • 相关阅读:
    OO第四次总结
    OO第三次总结
    C语言函数指针
    Java对象集合
    emacs下最牛逼的Markdown编辑方式
    OO第二次总结
    Git复习
    Java设计原则
    多线程学习笔记1
    OO第一次总结
  • 原文地址:https://www.cnblogs.com/mhy12345/p/4004654.html
Copyright © 2020-2023  润新知