BZOJ1040:骑士(基环树DP)

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

Input

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

Output

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

Input:

3

10 2

20 3

30 1

Output:

30

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

题意:N个点N条边,每个点有权值,求一些点,使得这些点的权值和最大,而且满足这些点不相邻。

思路:最大权值独立集,本来是NP问题。但,如果此题是树的话可以树形DP求。

但是这里是基环树,需要考虑树上有环,和一些单独的环,或者重边blabla,情况可能有些复杂。

经过WAM队的讨论,由支老板想出了拆掉环上一边再DP的思路。后来发现这可能就是基环树DP

 注意:此题的图不一定是连通的,所以有两种图,一个带环的树,二是环,都需要讨论到。

分别以拆边的两顶点作为根求树形DP的时候记住更新值。

(没什么写的,如果后面对此类DP有更多的接触再回来补)。

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<iostream>
using namespace std;
#define ll long long
const int maxn=1000010;
int Laxt[maxn],Next[maxn<<1],To[maxn<<1],cnt=1;
int w[maxn],vis[maxn],es,ey,cut_e; ll dp[maxn][2],ans;
void add(int u,int v)
{
    Next[++cnt]=Laxt[u];
    Laxt[u]=cnt;
    To[cnt]=v;
}
void dfs(int u,int pre)
{
    vis[u]=1;
    for(int i=Laxt[u];i;i=Next[i]){
        int v=To[i];
        if(v==pre) continue;
        if(!vis[v]) dfs(v,u);
        else {
            cut_e=i; es=v; ey=u;
        }
    }
}
void treedp(int u,int pre)
{
    dp[u][1]=w[u]; dp[u][0]=0; //重新赋值
    for(int i=Laxt[u];i;i=Next[i]){
        int v=To[i];
        if(v==pre) continue;
        if(i==cut_e||i==(cut_e^1)) continue;
        treedp(v,u);
        dp[u][0]+=max(dp[v][1],dp[v][0]);
        dp[u][1]+=dp[v][0];
    }
}
int main()
{
    int i,x,N;
    scanf("%d",&N);
    for(i=1;i<=N;i++){
        scanf("%d%d",&w[i],&x);
        add(i,x); add(x,i);
    }
    for(i=1;i<=N;i++){
        if(vis[i]) continue;
        dfs(i,-1);
        treedp(es,-1);
        ll tmp=dp[es][0]; //必须保留一下,因为两次根不同,dp结果要变,我就是这里WA了。
        treedp(ey,-1);
        ans+=max(tmp,dp[ey][0]);
        //错误:ans+=max(dp[es][0],dp[ey][0])。
    }
    printf("%lld\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/hua-dong/p/8511745.html

时间: 2024-11-09 11:43:17

BZOJ1040:骑士(基环树DP)的相关文章

【bzoj1040】[ZJOI2008]骑士 并查集+基环树dp

题目描述 Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各界的赞扬.最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争.战火绵延五百里,在和平环境中安逸了数百年的Z国又怎能抵挡的住Y国的军队.于是人们把所有的希望都寄托在了骑士团的身上,就像期待有一个真龙天子的降生,带领正义打败邪恶.骑士团是肯定具有打败邪恶势力的能力的,但是骑士们互相之间往往有一些矛盾.每个骑士都有且仅有一个自己最厌恶的骑士(当然不是他自己),他是绝对不会与自己最厌恶

[noi2013]快餐店 基环树dp,单调队列维护最大值和次大值

#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 220000 #define inf 0x3ffffffffffffffLL typedef long long ll; int v[N],e[N],ne[N],nn,w[N]; void add(int x,int y,int z){ ne[++nn

[CSP-S模拟测试]:卡常题/b(基环树+DP)

题目描述 $ρ$有一个二分连通无向图,$X$方点.$Y$方点均为$n$个(编号为$1\sim n$).这个二分图比较特殊,每一个$Y$方点的度为$2$,一条黑色边,一条白色边.所有黑色边权值均为$a$,所有白色边权值均为$b$.选择一个$X$方点,代价为连接的所有边的权值之和.激活一个$Y$方点,需要选择至少一个与之相邻的$X$方点.现在,$ρ$想激活每个$Y$方点,他想知道最小的总代价.不过$ρ$很善良,他给你开了$O2$优化.这样你就不会被卡常了.当然,除非你真的连读入优化都不想写,或者常数

BZOJ 1040: [ZJOI2008]骑士(基环树dp)

http://www.lydsy.com/JudgeOnline/problem.php?id=1040 题意: 思路: 这是基环树,因为每个人只会有一个厌恶的人,所以每个节点只会有一个父亲节点,但是根节点也是有父亲节点的,所以在树中肯定是存在一个环的,只要删除该环中的任意一条边,那么就能将该图变成一颗树. 如果是树的话,那就很简单了,d[u][0/1] dp求解即可. 现在假设删除的边是e,两端的节点分别是u,v,首先对u为根的树作一次dp,最后取d[u][0](v取不取都无所谓),不能取d[

bzoj1040(ZJOI2008)骑士——基环树

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1040 基环树的模板. 套路就是把环断开,先把一端作为根节点,强制不选:再把另一端作为根节点,强制不选. 人家的这个判断环的方法真好!还顺便没有连上环的那条边,省下了在函数里判断. 别忘了有多棵基环树! #include<iostream> #include<cstdio> #include<cstring> #define ll long long using n

luogu2607/bzoj1040 [ZJOI2008]骑士 (基环树形dp)

N个点,每个点发出一条边,那么这个图的形状一定是一个基环树森林(如果有重边就会出现森林) 那我做f[0][x]和f[1][x]分别表示对于x子树,x这个点选还是不选所带来的最大价值 然后就变成了这好几个环上不能选相邻的点,最大的价值和 我们把这个环从N到1处断开,然后钦定一下1选还是不选,统计一下答案就可以了. 1 #include<bits/stdc++.h> 2 #define pa pair<int,int> 3 #define ll long long 4 using na

【BZOJ】1040: [ZJOI2008]骑士 环套树DP

[题意]给定n个人的ai和bi,表示第i个人能力值为ai且不能和bi同时选择,求能力值和最大的选择方案.n<=10^6. [算法]环套树DP(基环树) [题解]n个点n条边--基环森林(若干环套树子图). 若原图是树,经典DP做法:f[i][0/1]表示i点选或不选的最大能力值和,则f[i][0]=Σmax{f[j][0],f[j][1]},f[i][1]=Σf[j][0]+a[i],j=son[i]. 找环:dfs到访问过的点,标记环上的一条边. 破环:和普通树上DP唯一的区别是,标记边两端不

[bzoj2878][Noi2012]迷失游乐园(基环树dp)

bzoj luogu 题意:一颗数或是基环树,随机从某个点开始一直走,不走已经到过的点,求无路可走时的路径长期望. 对于一棵树: 用两个$dp$数组分别记录从这个点起向上向下走的期望 向下走的$dp$不用多说 向上走的$dp$: 对于从$u$计算$v$的dp $dp[v]$应当是从u向周围引出所有路径减去走向t的路径的期望后再除以$deg_{u}-1$ 对于基环树: 环上的点很少. 此时环上的点的向上$dp$指从u出发向环上两头走的期望. 如何计算:对于环上每一个点都向环的两头各dp一次取平均值

[BZOJ1040][ZJOI2008]骑士(环套树dp)

1040: [ZJOI2008]骑士 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 5816  Solved: 2263[Submit][Status][Discuss] Description Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各 界的赞扬.最近发生了一件可怕的事情,邪恶的Y国发动了一场针对Z国的侵略战争.战火绵延五百里,在和平环境 中安逸了数百年的Z国又怎能抵挡的住Y国的军队.于是人