• 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;
    }
    
  • 相关阅读:
    Linux内核中的jiffies 以及时间的获取time
    linux2.6内核启动流程简述
    qt 显示控件 导致频闪
    V4L2应用程序框架
    linux 目标机 windows 图形界面ftp登录
    linux2.4内核启动流程简述及2410主频修改
    块设备驱动编写总结一(ZT)
    backlight misc驱动范例 及应用程序范例
    如何通过结构中的某个成员地址获取结构本身的指针???
    我是怎么招聘程序员的
  • 原文地址:https://www.cnblogs.com/rui-4825/p/12769180.html
Copyright © 2020-2023  润新知