码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 1040:[ZJOI2008]骑士(环套外向树+树形DP)

时间:2017-07-13 16:01:49      阅读:80      评论:0      收藏:0      [点我收藏+]

标签:algorithm   roo   vector   blog   root   cpp   can   return   oid   

 

【题目链接】 http://www.lydsy.com/JudgeOnline/problem.php?id=1040

 

【题目大意】

  给出环套外向树森林,求最大权独立集。

 

【题解】

  我们对于每个连通块,找到环上的一条边拆开,对于边的两端分别做树形DP,
  假设两端点位x和y,那么不包含x的dp值涵盖了是否包含y两种情况,
  同理,以y为根的也是,因为边的两端不能同时取到,因此对于两者取最大值即可。
  代码中f[x]表示包含x的dp值,g[x]表示不包含x的dp值。

 

【代码】

#include <cstdio>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
const int N=1000010;
vector<int> v[N],id[N];
LL g[N],f[N],ans;
int ban,n,c[N],x,vis[N],root,_root,idn=0;
void dfs(int x,int fx){  
    vis[x]=1;  
    for(int i=0;i<v[x].size();i++){
        int y=v[x][i]; 
        if(y==fx)continue;  
        if(!vis[y])dfs(y,x);  
        else{root=y;_root=x;ban=id[x][i];}  
    }  
}  
void TreeDP(int x,int fx){
    f[x]=c[x],g[x]=0;
    for(int i=0;i<v[x].size();i++){
        int y=v[x][i];
        if(y==fx)continue;
        if(id[x][i]==ban||id[x][i]==(ban^1))continue;
        TreeDP(y,x);
        f[x]+=g[y]; g[x]+=max(f[y],g[y]);
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&c[i],&x);
        v[x].push_back(i); 
        id[x].push_back(idn++);
        v[i].push_back(x);
        id[i].push_back(idn++);
    }
    for(int i=1;i<=n;i++){
        if(!vis[i]){
            dfs(i,-1);
            TreeDP(root,-1);
            LL tmp=g[root];
            TreeDP(_root,-1);
            tmp=max(tmp,g[_root]);
            ans+=tmp;
        }
    }printf("%lld\n",ans);
    return 0;
}

BZOJ 1040:[ZJOI2008]骑士(环套外向树+树形DP)

标签:algorithm   roo   vector   blog   root   cpp   can   return   oid   

原文地址:http://www.cnblogs.com/forever97/p/bzoj1040.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!