一道变形DP——骑士(洛谷)

来来来!!!

看题了!!!

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

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

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

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

为了描述战斗力,我们将骑士按照 11 至 nn 编号,给每名骑士一个战斗力的估计,一个军团的战斗力为所有骑士的战斗力总和。

输入格式

第一行包含一个整数 nn,描述骑士团的人数。

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

输出格式

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

输入输出样例

输入 #1
3
10 2
20 3
30 1
输出 #1
30

说明/提示

数据规模与约定

对于 30\%30% 的测试数据,满足 n \le 10n10;

扫描二维码关注公众号,回复: 11080448 查看本文章

对于 60\%60% 的测试数据,满足 n \le 100n100;

对于 80\%80% 的测试数据,满足 n \le 10 ^4n104。

对于 100\%100% 的测试数据,满足 1\le n \le 10^61n106,每名骑士的战斗力都是不大于 10^6106 的正整数。

——————————————————————————————————————————————————————————————————————

想到了神马

来,在看一道简单题。

来来来!!!

看题了!!!

P1352 没有上司的舞会

提交19.06k
通过12.39k
时间限制1.00s
内存限制125.00MB
题目提供者yeszy
历史分数100
 提交记录   查看题解

标签

 查看算法标签
进入讨论版

相关讨论

 查看讨论

推荐题目

 查看推荐
 展开

题目描述

某大学有 nn 个职员,编号为 1\ldots n1n。

他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。

现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数 r_iri,但是呢,如果某个职员的直接上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。

所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。

输入格式

输入的第一行是一个整数 nn。

第 22 到第 (n + 1)(n+1) 行,每行一个整数,第 (i+1)(i+1) 行的整数表示 ii 号职员的快乐指数 r_iri

第 (n + 2)(n+2) 到第 (2n + 1)(2n+1) 行,每行输入一对整数 l, kl,k,代表 kk 是 ll 的直接上司。

输出格式

输出一行一个整数代表最大的快乐指数。

输入输出样例

输入 #1
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
输出 #1
5

说明/提示

数据规模与约定

对于 100\%100% 的数据,保证 1\leq n \leq 6 \times 10^31n6×103,-128 \leq r_i\leq 127128ri127,1 \leq l, k \leq n1l,kn,且给出的关系一定是一棵树。

如果大家这道题都不会的话,建议先去做这道题。

OK,那么如果你已经做出了这道题。

那么骑士这道题对你也就没有深莫难度了。

下面是骑士的题解:

————————————————————————————————————————————————————————————————————

树形DP,没有上司的舞会的模型。。。

根据题目可以知道, 每一个联通块里有且只有一个环, 所以我们找到这个环然后从中间把它断开, 对断开的两个端点u1, u2, 分别舞会。

设dp[u][0]为不选u, dp[u][1]为选u,

那么这个联通块答案就是max(dp[u1][0], dp[u2][0])。

注意有好多联通块。对于所有联通块跑dp,加起来就是答案

大家是不是懂了。

下面是伪代码:

//写一下伪代码
//在存的时候存一下每个人最讨厌的人为他的父亲
//对每个没访问的点DFS
//在这个没访问的点所在的连通块上找环
//找到以后强制不选它的父亲对它进行DP
//然后强制不选它对它的父亲进行DP
//然后取一个最大值即可
//在DP里面
//先考虑f[x][0]是不选x,初始值为0
//f[x][1]是选x,初值为val[x]
//这是一个很好的赋值方法
//然后跑DP就行了

然后是正品:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #define maxn 2000000
 6 using namespace std;
 7 int n,cnt;
 8 long long ans;
 9 int root;
10 long long f[maxn][2];
11 int head[maxn],val[maxn],vis[maxn],fa[maxn];
12 struct edge{
13     int pre,to;
14 }e[maxn];
15 int in(){
16     char a=getchar();
17     while(a<'0'||a>'9'){
18         a=getchar();
19     }
20     int t=0;
21     while(a<='9'&&a>='0'){
22         t=(t<<1)+(t<<3)+a-'0';
23         a=getchar();
24     }
25     return t;
26 } 
27 void add(int from,int to){
28     e[++cnt].pre=head[from];
29     e[cnt].to=to;
30     head[from]=cnt;
31 }
32 void dp(int now){
33     vis[now]=1;
34     f[now][0]=0,f[now][1]=val[now];
35     for(int i=head[now];i;i=e[i].pre){
36         int go=e[i].to;
37         if(go!=root){
38             dp(go);
39             f[now][0]+=max(f[go][1],f[go][0]);
40             f[now][1]+=f[go][0];
41         }
42         else{
43             f[go][1]=-maxn;
44         }
45     }
46 }
47 void find_circle(int x){
48     vis[x]=1;
49     root=x;
50     while(!vis[fa[root]]){
51         root=fa[root];
52         vis[root]=1;
53     }//找环
54     dp(root);
55     long long t=max(f[root][0],f[root][1]);
56     vis[root]=1;
57     root=fa[root]; 
58     dp(root);
59     ans+=max(t,max(f[root][0],f[root][1]));
60     return;
61 }
62 int main(){
63     //freopen("a.in","r",stdin);
64     n=in();
65     for(int i=1;i<=n;i++){
66         val[i]=in();
67         int x=in();
68         add(x,i);
69         fa[i]=x;
70     }
71     for(int i=1;i<=n;i++){
72         if(!vis[i]){
73             find_circle(i);
74         }
75     }
76     printf("%lld\n",ans);
77     return 0;
78 }

这道题比较考验代码能力。

大家应该独立完成。

猜你喜欢

转载自www.cnblogs.com/DZN2004/p/12762887.html