• bzoj 1040: [ZJOI2008]骑士 树形dp


    题目链接

    1040: [ZJOI2008]骑士

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 3054  Solved: 1162
    [Submit][Status][Discuss]

    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的正整数。

     
    根据题目可以知道, 每一个联通块里有且只有一个环, 所以我们找到这个环然后从中间把它断开, 对断开的两个端点u1, u2, 分别dfs。
    设dp[u][0]为不选u, dp[u][1]为选u,
    那么答案就是max(dp[u1][0], dp[u2][0])。
     
    注意有好多联通块, 一开始没想到狂wa不止。
    #include <iostream>
    #include <vector>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <map>
    #include <set>
    #include <string>
    #include <queue>
    #include <stack>
    #include <bitset>
    using namespace std;
    #define pb(x) push_back(x)
    #define ll long long
    #define mk(x, y) make_pair(x, y)
    #define lson l, m, rt<<1
    #define mem(a) memset(a, 0, sizeof(a))
    #define rson m+1, r, rt<<1|1
    #define mem1(a) memset(a, -1, sizeof(a))
    #define mem2(a) memset(a, 0x3f, sizeof(a))
    #define rep(i, n, a) for(int i = a; i<n; i++)
    #define fi first
    #define se second
    typedef pair<int, int> pll;
    const double PI = acos(-1.0);
    const double eps = 1e-8;
    const int mod = 1e9+7;
    const int inf = 1061109567;
    const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
    const int maxn = 1e6+5;
    int head[maxn*2], num, u1, u2, a[maxn], vis[maxn], E;
    ll dp[maxn][2];
    struct node
    {
        int to, nextt;
    }e[maxn*2];
    void add(int u, int v) {
        e[num].to = v, e[num].nextt = head[u], head[u] = num++;
    }
    void init() {
        num = 0;
        mem1(head);
    }
    void get_circle(int u, int from) {
        vis[u] = 1;
        for(int i = head[u]; ~i; i = e[i].nextt) {
            int v = e[i].to;
            if((i^1) == from)
                continue;
            if(vis[v]) {
                u1 = u, u2 = v;
                E = i;
                continue ;
            }
            get_circle(v, i);
        }
    }
    void dfs(int u, int from) {
        dp[u][1] = a[u];
        dp[u][0] = 0;
        for(int i = head[u]; ~i; i = e[i].nextt) {
            int v = e[i].to;
            if((i^1) == from)
                continue;
            if(i == E || (i^1)==E)
                continue;
            dfs(v, i);
            dp[u][1] += dp[v][0];
            dp[u][0] += max(dp[v][1], dp[v][0]);
        }
    }
    int main()
    {
        int n, x;
        cin>>n;
        init();
        for(int i = 1; i<=n; i++) {
            scanf("%d%d", &a[i], &x);
            add(i, x);
            add(x, i);
        }
        ll ans = 0;
        for(int i = 1; i<=n; i++) {
            if(vis[i])
                continue;
            get_circle(i, -1);
            dfs(u1, -1);
            ll tmp = dp[u1][0];
            dfs(u2, -1);
            tmp = max(tmp, dp[u2][0]);
            ans += tmp;
        }
        cout<<ans<<endl;
        return 0;
    }
     
  • 相关阅读:
    poj 1328 Radar Installation (贪心)
    hdu 2037 今年暑假不AC (贪心)
    poj 2965 The Pilots Brothers' refrigerator (dfs)
    poj 1753 Flip Game (dfs)
    hdu 2838 Cow Sorting (树状数组)
    hdu 1058 Humble Numbers (DP)
    hdu 1069 Monkey and Banana (DP)
    hdu 1087 Super Jumping! Jumping! Jumping! (DP)
    必须知道的.NET FrameWork
    使用记事本+CSC编译程序
  • 原文地址:https://www.cnblogs.com/yohaha/p/5229775.html
Copyright © 2020-2023  润新知