[BZOJ 1040][ZJOI2008]骑士

1040: [ZJOI2008]骑士

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 5403  Solved: 2060
[Submit][Status][Discuss]

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的正整数。

题解

分析题意可以得到这应该是个最大权独立集...

然而普适的最大权独立集问题并不可做...这个问题肯定有特殊的地方. 我们发现每个点主动连出去的边有且仅有一条, 我们可以发现这是个环套树.

如果是树的话直接一个 $DP$ 怼上去就可以了, 而对于环套树, 我们可以先进行一遍 $DFS$ 找找是否有环, 没有环直接按树来 $DP$ , 如果有环的话, 任意选一条边断掉转化成树, 标记这条边连接的两个结点, 两个结点中强制某一个不能选, $DP$ 一遍, 换另一个结点强制不选再跑一遍, 在两种情况下取最大值.

断边的过程可以通过维护全局标记实现, 对于与全局标记相等的边直接不走就可以了, 对于强制不选, 则可以在跑一遍 $DP$ 后强行将强制不选的那个结点选中时得到的最大值赋为 $-\infty$ 即可

参考代码

GitHub

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <climits>
 4 #include <cstdlib>
 5 #include <iostream>
 6 #include <algorithm>
 7 
 8 const int MAXN=1e6+10;
 9 
10 struct Edge{
11     int from;
12     int to;
13     int ID;
14     Edge* next;
15 };
16 Edge E[MAXN*2];
17 Edge* head[MAXN];
18 Edge* top=E;
19 
20 int n;
21 int disableV;
22 int disableE;
23 int cut1,cut2;
24 long long ans,tmp;
25 bool visited[MAXN];
26 long long val[MAXN];
27 long long dp[MAXN][2];
28 
29 void DP(int,int);
30 void DFS(int,int);
31 void Initialize();
32 void Insert(int,int,int);
33 
34 int main(){
35     Initialize();
36     for(int i=1;i<=n;i++){
37         if(visited[i])
38             continue;
39         else{
40             DFS(i,0);
41             disableV=cut1;
42             DP(i,0);
43             tmp=std::max(dp[i][0],dp[i][1]);
44             disableV=cut2;
45             DP(i,0);
46             tmp=std::max(tmp,std::max(dp[i][0],dp[i][1]));
47             ans+=tmp;
48         }
49     }
50     printf("%lld\n",ans);
51     return 0;
52 }
53 
54 void DFS(int root,int prt){
55     visited[root]=true;
56     for(Edge* i=head[root];i!=NULL;i=i->next){
57         if(i->ID==prt)
58             continue;
59         else if(visited[i->to]){
60             cut1=root;
61             cut2=i->to;
62             disableE=i->ID;
63         }
64         else
65             DFS(i->to,i->ID);
66     }
67 }
68 
69 void DP(int root,int prt){
70     dp[root][0]=0;
71     dp[root][1]=val[root];
72     for(Edge* i=head[root];i!=NULL;i=i->next){
73         if(i->ID==disableE||i->ID==prt)
74             continue;
75         DP(i->to,i->ID);
76         dp[root][0]+=std::max(dp[i->to][0],dp[i->to][1]);
77         dp[root][1]+=dp[i->to][0];
78     }
79     if(root=disableV)
80         dp[root][1]=LLONG_MIN;
81 }
82 
83 void Initialize(){
84     scanf("%d",&n);
85     int tmp;
86     for(int i=1;i<=n;i++){
87         scanf("%d%d",val+i,&tmp);
88         Insert(i,tmp,i);
89         Insert(tmp,i,i);
90     }
91 }
92 
93 inline void Insert(int from,int to,int ID){
94     top->to=to;
95     top->ID=ID;
96     top->from=from;
97     top->next=head[from];
98     head[from]=top++;
99 }
Backup

 

 

posted @ 2017-10-17 21:40  rvalue  阅读(299)  评论(0编辑  收藏  举报