山东济南彤昌机械科技有限公司 山东济南江鹏工贸游有限公司

bzoj 1040 [ZJOI2008]骑士(基环外向树,树形DP)

 

【题目链接】

 

    http://www.lydsy.com/JudgeOnline/problem.php?id=1040

   

【题意】

 

    给一个基环森林,每个点有一个权值,求一个点集使得点集中的点无边相连且权值和最大。

 

【思路】

 

    注意题目中的有向边其实就是无向边。然后有多个联通块,每个联通块中有且仅有一个环。

    如果没有环的话可以用树形DP,解决这个问题。

    设f[i][0],f[i][1]分别表示以i为根,不选/选i时的最大权值。则有转移式:

        f[i][0]=sigma{ max(f[son(i)][0],f[son(i)][1]) }

        f[i][1]=sigma{ f[son(i)][0] }

    对于一个环,我们任选一条边拆开,然后以边的两点U,V为根做树形DP,再考虑边UV存在,有两种情况:

  1) 强制不选U,V任意,环的贡献为以U做DP的f[U][0]

  2) 强制不选V,U任意,环的贡献为以V做DP的f[V][0]

 

【科普】

 

    基环外向树就是一棵树加一条边(好厉害的名字<_<

 

【代码】

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<iostream>
 4 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
 5 using namespace std;
 6 
 7 typedef long long ll;
 8 const int N = 1e6+10;
 9 
10 struct Edge {
11     int v,nxt;
12 }e[N<<1];
13 int en=1,front[N];
14 void adde(int u,int v)
15 {
16     en++; e[en].v=v,e[en].nxt=front[u],front[u]=en;
17 }
18 
19 int n,w[N],vis[N];
20 ll f[N][2];
21 
22 ll read()
23 {
24     char c=getchar(); ll f=1,x=0;
25     while(!isdigit(c)) {if(c=='-') f=-1; c=getchar(); };
26     while(isdigit(c)) x=x*10+c-'0',c=getchar();
27     return x*f;    
28 }
29 
30 int U,V,E;
31 void dfs(int u,int fa) 
32 {
33     vis[u]=1;
34     for(int i=front[u];i;i=e[i].nxt) {
35         if((i^1)==fa) continue;
36         int v=e[i].v;
37         if(vis[v]) {
38             U=u; V=v; E=i;
39             continue;
40         }
41         dfs(v,i);
42     }
43 }
44 void treedp(int u,int fa,int ban)
45 {
46     f[u][1]=w[u],f[u][0]=0;
47     for(int i=front[u];i;i=e[i].nxt) {
48         if((i^1)==fa) continue;
49         if(i==ban||(i^1)==ban) continue;
50         int v=e[i].v;
51         treedp(v,i,ban);
52         f[u][0]+=max(f[v][1],f[v][0]);
53         f[u][1]+=f[v][0];
54     }
55 }
56 
57 int main()
58 {
59     n=read();
60     int v;
61     FOR(i,1,n) {
62         w[i]=read(),v=read();
63         adde(i,v),adde(v,i);
64     }
65     ll ans=0;
66     FOR(i,1,n) if(!vis[i]) {
67         dfs(i,-1);
68         treedp(U,-1,E);
69         ll tmp=f[U][0];
70         treedp(V,-1,E);
71         tmp=max(tmp,f[V][0]);
72         ans+=tmp;
73     }
74     printf("%lld",ans);
75     return 0;
76 }

 

posted on 2016-03-14 11:41  hahalidaxin  阅读(513)  评论(1编辑  收藏  举报