bzoj 1040: [ZJOI2008]骑士

Description

  Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英。他们劫富济贫,惩恶扬善,受到社会各
界的赞扬。最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争。战火绵延五百里,在和平环境
中安逸了数百年的Z国又怎能抵挡的住Y国的军队。于是人们把所有的希望都寄托在了骑士团的身上,就像期待有一
个真龙天子的降生,带领正义打败邪恶。骑士团是肯定具有打败邪恶势力的能力的,但是骑士们互相之间往往有一
些矛盾。每个骑士都有且仅有一个自己最厌恶的骑士(当然不是他自己),他是绝对不会与自己最厌恶的人一同出
征的。战火绵延,人民生灵涂炭,组织起一个骑士军团加入战斗刻不容缓!国王交给了你一个艰巨的任务,从所有
的骑士中选出一个骑士军团,使得军团内没有矛盾的两人(不存在一个骑士与他最痛恨的人一同被选入骑士军团的
情况),并且,使得这支骑士军团最具有战斗力。为了描述战斗力,我们将骑士按照1至N编号,给每名骑士一个战
斗力的估计,一个军团的战斗力为所有骑士的战斗力总和。

Input

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

Output

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

Sample Input

3
10 2
20 3
30 1

Sample Output

30

HINT

 

N ≤ 1 000 000,每名骑士的战斗力都是不大于 1 000 000的正整数。

 

 

思路

乍一看,没什么思路,

再一看,一共有n个点,连了m条边,求最大独立集?

基环树裸题啊。(此处是森林)

一棵树,多了一条边使得其产生一个环,就叫基环树。

一般的做法是把环拎出来,

想象着环上每个点下面挂着子树,

然后对子树查询,最后放到环上进行查询。

而这题就更方便了。

 

假设只有一棵树,定义数组f[100001][2]

f[i][0]表示i这个点不选时的子树最优解

f[i][1]表示i这个点选上时的子树最优解

dp方程非常显然。

再考虑基环树。

只要找出环上任意一条边a-b,

那么a,b中至少有一个不被选中,

我们可以割掉a-b这条边,

然后从a开始树形dp,记f[a][0];从b开始树形dp,记f[b][0],

那么ans+=max(f[a][0],f[b][0])即可

 

 

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 using namespace std;
 4 #define ref(i,x,y)for(int i=x;i<=y;++i)
 5 #define eef(i,x)for(int i=head[x],y=e[i].to;i;i=e[i].next,y=e[i].to)if(y!=fa)
 6 int read()
 7 {
 8     char c=getchar();int d=0,f=1;
 9     for(;c<'0'||c>'9';c=getchar())if(c=='-')f=-1;
10     for(;c>='0'&&c<='9';d=d*10+c-48,c=getchar());
11     return d*f;
12 }
13 typedef long long ll;
14 const int N=1000001;
15 int n,cnt,xx,yy;
16 int head[N],vis[N],w[N],pt[N];
17 ll f[N][2];
18 struct xint{int to,next;}e[N*2];
19 void addedge(int x,int y)
20 {
21     e[++cnt]=(xint){y,head[x]};head[x]=cnt;
22     e[++cnt]=(xint){x,head[y]};head[y]=cnt;
23 }
24 void dfs1(int fa,int x)
25 {
26     vis[x]=1;
27     eef(i,x)if(!vis[y])dfs1(x,y);else xx=x,yy=y;
28 }
29 void dfs2(int fa,int x)
30 {
31     f[x][0]=0;
32     f[x][1]=w[x];
33     eef(i,x)
34     {
35         if(x==xx&&y==yy||y==xx&&x==yy)continue;
36         dfs2(x,y);
37         f[x][1]+=f[y][0];
38         f[x][0]+=max(f[y][0],f[y][1]);
39     }
40 }
41 void work()
42 {
43     ll ans=0;
44     ref(i,1,n)if(!vis[i])
45     {
46         xx=yy=0;
47         dfs1(0,i);
48         ll tmp=0;
49         if(!xx&&!yy)
50         {
51             dfs2(0,i);
52             tmp=max(f[i][1],f[i][0]);
53         }
54         else
55         {
56             dfs2(0,xx);
57             tmp=f[xx][0];
58             dfs2(0,yy);
59             tmp=max(tmp,f[yy][0]);
60         }
61         ans+=tmp;
62     }
63     cout<<ans<<endl;
64 }
65 int main()
66 {
67     n=read();
68     ref(i,1,n)
69     {
70         w[i]=read();pt[i]=read();
71         if(pt[pt[i]]!=i)addedge(i,pt[i]);
72     }
73     work();
74 }

 

posted @ 2017-03-30 20:00  I_m_Eden  阅读(206)  评论(2编辑  收藏  举报