LOJ10162 骑士

ZJOI 2008

Z 国的骑士团是一个很有势力的组织,帮会中聚集了来自各地的精英。他们劫富济贫,惩恶扬善,受到了社会各界的赞扬。

可是,最近发生了一件很可怕的事情:邪恶的 Y 国发起了一场针对 Z 国的侵略战争。战火绵延五百里,在和平环境中安逸了数百年的 Z 国又怎能抵挡得住 Y 国的军队。于是人们把所有希望都寄托在了骑士团身上,就像期待有一个真龙天子的降生,带领正义打败邪恶。

骑士团是肯定具备打败邪恶势力的能力的,但是骑士们互相之间往往有一些矛盾。每个骑士有且仅有一个他自己最厌恶的骑士(当然不是他自己),他是绝对不会与最厌恶的人一同出征的。

战火绵延,人们生灵涂炭,组织起一个骑士军团加入战斗刻不容缓!国王交给你了一个艰巨的任务:从所有骑士中选出一个骑士军团,使得军内没有矛盾的两人,即不存在一个骑士与他最痛恨的人一同被选入骑士团的情况,并且使这支骑士军团最富有战斗力。

为描述战斗力,我们将骑士按照 1 至 N 编号,给每位骑士估计一个战斗力,一个军团的战斗力为所有骑士的战斗力之和。

输入格式

输入第一行包含一个正整数 N,描述骑士团的人数;

接下来 N 行每行两个正整数,按顺序描述每一名骑士的战斗力和他最痛恨的骑士。

输出格式

输出包含一行,一个整数,表示你所选出的骑士军团的战斗力。

样例

样例输入

3
10 2
20 3
30 1

样例输出

30

数据范围与提示

对于 30% 的数据,满足 N10;

对于 60% 的数据,满足 N100;

对于 80% 的数据,满足N10^4;

对于 100% 的数据,满足 N10^6,且每名骑士的战斗力都是不大于 10^6 的正整数。

_____________________________________________________________________________________________

树形动归,n个点,n条边,那么整个图构成多个联通块,每个块内要么是一棵树,要么是一棵树加一条边构成一个环。

如果是树,直接动归就可以了。

f[u][0]:表示不选当前点的最大战力

f[u][1]:表示选当前点的最大战力

f[u][0]=sum( max( f[v][0],f[v][1] ) )

f[u][1]=sum( f[v][0] )+zl[u];

如果内部是一个树加边,那么环上断开一条边,边的两个端点u,v,他们不能同时取。所以只要求f[u][0]和f[v][0]的较大值就可以了。

_____________________________________________________________________________________________

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn=1e6+10;
 5 int n;
 6 long long ans;
 7 ll zl[maxn];
 8 int hen[maxn];
 9 struct edge
10 {
11     int u,v,nxt;
12 }e[maxn<<1];
13 int head[maxn],js;
14 void addage(int u,int v)
15 {
16     e[++js].u=u;e[js].v=v;
17     e[js].nxt=head[u];head[u]=js;
18 }
19 bool vis[maxn];
20 long long f[maxn][2];
21 int h1,h2,bz=0,root;
22 void dfs(int u,int fa)
23 {
24     if(vis[u]==0)
25     {
26         vis[u]=1;
27     }
28     else 
29     {
30         h1=u;h2=fa;bz=1;
31         return;
32     }
33     for(int i=head[u];i;i=e[i].nxt)
34     {
35         int v=e[i].v;
36         if(v!=fa)dfs(v,u);
37     }
38 }
39 void dp(int u,int fa)
40 {
41     f[u][0]=0;
42     f[u][1]=zl[u];
43     for(int i=head[u];i;i=e[i].nxt)
44     {
45         int v=e[i].v;
46         if(v!=fa && v!=root)
47         {
48             dp(v,u);
49             f[u][0]+=max(f[v][0],f[v][1]);
50             f[u][1]+=f[v][0];
51         }
52     }
53 }
54 int main()
55 {
56     scanf("%d",&n);
57     for(int i=1;i<=n;++i)
58     {
59         scanf("%d%d",&zl[i],&hen[i]);
60         if(hen[hen[i]]==i)continue;
61         addage(i,hen[i]);
62         addage(hen[i],i);
63     }
64     for(int i=1;i<=n;++i)
65         if(!vis[i])
66         {
67             h1=h2=bz=0;
68             dfs(i,0);
69             if(bz==0)
70             {
71                 root = i;
72                 dp(i,0);
73                 ans+=max(f[i][0],f[i][1]);
74             }
75             else
76             {
77                 root=h1;dp(h1,h2);long long tp=f[h1][0];
78                 root=h2;dp(h2,h1);
79                 ans+=max(tp,f[h2][0]);
80             }
81         }
82     cout<<ans;
83     return 0;
84 }
View Code
原文地址:https://www.cnblogs.com/gryzy/p/10179705.html