zoukankan      html  css  js  c++  java
  • BZOJ1040: [ZJOI2008]骑士 (树形DP)

    题意:1e6个骑士 每个骑士有一个战斗力有一个讨厌的人

       选择一些人组成军团使得军团战斗力和最大 且每个人不会和自己讨厌的人都在军团里

    题解:每个点和自己讨厌的点建一条双向边 因为你讨厌他 你不会和他同时出现

       n个点n条边 那么每一个独立的子集都是一棵带环树

       先dfs一遍找到形成环的地方 把他断掉

       分别以两个点做一次不能选相邻两个点的树形DP 且不选起点

    总结:树上的操作还是不熟 怎么找环断开边什么的

    #include <stdio.h>
    #include <algorithm>
    #include <iostream>
    #include <string.h>
    using namespace std;
    typedef long long ll;
    
    int n;
    struct node
    {
        int to, nex;
    }E[2000005];
    
    int head[2000005];
    int vis[1000005];
    int s[2000005];
    ll q[1000005];
    ll dp[1000005][3];
    int l, r;
    bool f;
    
    void dfs(int x, int fa)
    {
        vis[x] = 1;
    
        int c = head[x];
        for(int i = c; i && (!f); i = E[i].nex)
        {
            int v = E[i].to;
            if(v == fa) continue;
    
            if(vis[v])
            {
                s[i] = -1;      //表示将这两条边断开
                if((i & 1) == 1) s[i + 1] = -1;
                else s[i - 1] = -1;
    
                l = x; r = v; f = true;
                break;
            }
            dfs(v, x);
        }
    }
    
    void dfs1(int x, int fa, int cut)
    {
        vis[x] = true;       //可能找到环了 但这颗带环树还没搜完
        if(x != cut) dp[x][1] = q[x];
        else dp[x][1] = 0;
        dp[x][0] = 0;
    
        int c = head[x];
        for(int i = c; i; i = E[i].nex)
        {
            int v = E[i].to;
            if(v == fa) continue;
            if(s[i] == -1) continue;
    
            dfs1(v, x, cut);
            dp[x][1] += dp[v][0];
            dp[x][0] += max(dp[v][1], dp[v][0]);
        }
    }
    
    int main()
    {
        int cnt = 0;
        scanf("%d", &n);
        for(int i = 1; i <= n; i++)
        {
            int x;
            scanf("%lld%d", &q[i], &x);
            E[++cnt].to = x, E[cnt].nex = head[i], head[i] = cnt;
            E[++cnt].to = i, E[cnt].nex = head[x], head[x] = cnt;
        }
    
        ll ans = 0;
        for(int i = 1; i <= n; i++)
        {
            if(!vis[i])
            {
                f = false;      //任意独立x个点x条边 一定带环 所以不存在树了
                dfs(i, -1);
    
                ll o = 0;
                dfs1(l, -1, r);
                o = max(o, dp[l][0]); o = max(o, dp[l][1]);
                dfs1(r, -1, l);
                o = max(o, dp[r][0]); o = max(o, dp[r][1]);
                ans += o;
            }
        }
        printf("%lld
    ", ans);
    
        return 0;
    }
    /*
    5
    10 2
    10 3
    10 4
    10 2
    10 4
    5
    10 2
    25 3
    10 4
    16 2
    10 4
    */
    View Code
  • 相关阅读:
    【git】强制覆盖本地代码(与git远程仓库保持一致)
    ffmpeg CLI常用命令
    旧机改造步骤
    macbook air 2012 mid 安装 windows10 双系统遇到错误 no bootable device insert boot disk and press any key
    window、Linux 文本文件转换
    phalcon bug: model的findFirst会自动忽略一些空格
    oss2罗列所有文件
    如何让linux的history命令显示时间记录
    nginx 常用配置
    shell脚本 切换用户
  • 原文地址:https://www.cnblogs.com/lwqq3/p/9065835.html
Copyright © 2011-2022 走看看