【动态规划】【树形DP】[BZOJ 1040]骑士

首先可以发现肯定这个图是一个森林,而且在这个森林之中只有一个环,那么只要找到这个环上的任意一条边(删掉这条边)然后对这条边的两个端点分别作两次最大独立集,然后分别取两个点中不取的情况的最大值,然后这个值就是要找的了,因为只有一个环,所以我找环的方法是用并查集的方法。。

#include <cstdio>
//#include <conio.h>
#include <algorithm>
#include <cstring>
#include <vector>
#include <iostream>
#include <map>
using namespace std;
const int MAXN = 1000000;
int w[MAXN+10];
vector<int> vec[MAXN+10];
int fat[MAXN+10];
inline int findfa(int u){
    if(fat[u]) return findfa(fat[u]);
    return u;
}
pair<int, int> pos[MAXN+10];
int f1, f2, pcnt;
void addedge(int u, int v){
    f1=findfa(u); f2 = findfa(v);
    if(f1 == f2){
        pos[++pcnt] = make_pair(u, v);
        return ;
    }
    fat[f1] = f2;
    vec[u].push_back(v);
    vec[v].push_back(u);
}
long long f[MAXN+10], g[MAXN+10];
void dp(int u, int fa){
    f[u] = g[u] = 0;
    int Len = vec[u].size();
    for(int i=0;i<Len;i++) if(vec[u][i]!=fa && vec[u][i]!=-1){
        dp(vec[u][i], u);
        g[u] += 1LL * max(f[vec[u][i]], g[vec[u][i]]);
        f[u] += 1LL * g[vec[u][i]];
    }
    f[u] += 1LL * w[u];
}


int main(){
    int n, v;
    long long ans = 0;
    scanf("%d", &n);
    for(int i=1;i<=n;i++){
        scanf("%d", &w[i]);
        scanf("%d", &v);
        addedge(i, v);
    }
    for(int i=1;i<=pcnt;i++){
        dp(pos[i].first, -1);
        long long tmp = g[pos[i].first];
        dp(pos[i].second, -1);
        ans += max(tmp, g[pos[i].second]);
    }
    cout<<ans<<endl;

    return 0;
}

posted on 2015-07-15 10:44  JeremyGuo  阅读(145)  评论(0编辑  收藏  举报

导航