Loading

ZJOI2008 骑士(树型DP)

ZJOI2008 骑士

题目大意

给出n个人的战斗力和每个人讨厌的人,然后问最大能有多大的战斗力

solution

简单粗暴的题意,有一丢丢背包的感觉
那敢情就是DP了
有点像没有上司的舞会,,,
根据题意,骑士之间互相厌恶会形成一个环,任务就是找到这个环并且把它断开,然后对断开的两个端点分别求答案,然后取最优结果
设定当前点为u
断开的两个节点是u1和u2
选取当前点的状态记为1,不选的话就是0
那么数组就是dp[u][0],dp[u][1]
从这两个中间取最大值即可
最后将所有的DP值加和就是结果了

第一眼应为想到要找环,所以本来打算写Tarjan判连通块
然后去blogs验证思路的时候发现好像并不需要
用到了一个神奇的东东——拓扑排序
判环,拆分,统计入度和出度
求和得到结果即可

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;

inline int read(){
	int x = 0, w = 1;
	char ch = getchar();
	for(; ch > '9' || ch < '0'; ch = getchar()) if(ch == '-') w = -1;
	for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
	return x * w;
}

const int N = 1000000 + 10;
int head[N], cnt = 1, size[N], r1, r2,p[N];
struct Edge { 
    int to, next; 
} edges[N << 1];

bool vis[N], flag;
long long ans, f[N][2];
inline void add(int x, int y) {
    edges[++cnt].next = head[x];
    edges[cnt].to = y;
    head[x] = cnt;
}

inline void dfs(int x, int fa) {
    vis[x] = 1;
    size[++size[0]] = x;
    for (int i = head[x]; i; i = edges[i].next) {
        int v = edges[i].to;
        if (v == fa) continue;
        if (!vis[v]) dfs(v, x);
        else if (vis[v] && !flag) {
            flag = true;
            r1 = x, r2 = v;
        }
    }
}

inline void dfs2(int x, int fa) {
    f[x][0] = 0;
    f[x][1] = p[x];
    for (int i = head[x]; i; i = edges[i].next) {
        int v = edges[i].to;
        if (v && v != fa) {
            dfs2(v, x);
            f[x][1] += f[v][0];
            f[x][0] += max(f[v][0], f[v][1]);
        }
    }
}

inline void solve() {
    if (!flag) {
        int root = size[1];
        dfs2(root, -1);
        ans += max(f[root][0], f[root][1]);
    } else {
        long long maxv = -100;
        for (int i = head[r1]; i; i = edges[i].next) {
            if (edges[i].to == r2) {
                edges[i].to = 0;
                edges[i ^ 1].to = 0;
                break;
            }
        }
        dfs2(r1, -1);
        maxv = max(maxv, f[r1][0]);
        dfs2(r2, -1);
        maxv = max(maxv, f[r2][0]);
        ans += maxv;
    }
}

int n;
int main() {
    n = read();
    int x, y;
    for (int i = 1; i <= n; i++){
        p[i] = read();
        x = read();
        add(x, i);
        add(i, x);
    }
    for (int i = 1; i <= n; i++) {
        if (!vis[i]) {
            size[0] = 0;
            flag = false;
            dfs(i, -1);
            solve();
        }
    }
    printf("%lld", ans);
    return 0;
}
posted @ 2020-04-24 18:08  Gary_818  阅读(114)  评论(0编辑  收藏  举报