bzoj1040: [ZJOI2008]骑士

本文解析了一道经典的环套树动态规划问题,通过转换为无向环套树的形式,并利用树形DP来求解最优解,即在给定的基环内向树森林中选取节点,使得权值和最大化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

链接

  http://www.lydsy.com/JudgeOnline/problem.php?id=1040

题解

  1A二连击!
  题目显然给了一个基环内向树森林,说是一个点和它指向的点中只能选择一个,你要安排选择哪些点,使权值和最大。
  显然可以转成无向环套树,因为原来的图就等价于相邻的两个点只能选择其一。
  然后就可以找到环,随便找环上两个点u和v,断掉一条连边,然后分别强制不选u和v,做树形dp,ans取最大值就好了。
  注意是森林!
  还有个地方,就是可能出现两个点之间有两条边的情况,因此断边的时候应该记录边的序号,而不是记录点对序号。

代码

//环套树、动态规划
#include <cstdio>
#include <algorithm>
#define maxn 1000002
#define ll long long
using namespace std;
int head[maxn], to[maxn<<1], nex[maxn<<1], N, u, v, cut, tot=1;
ll f[maxn][2], w[maxn];
bool vis[maxn];
void adde(ll a, ll b){to[++tot]=b;nex[tot]=head[a];head[a]=tot;}
int read(int x=0)
{
    char c=getchar();
    while(c<48 or c>57)c=getchar();
    while(c>=48 and c<=57)x=(x<<1)+(x<<3)+c-48,c=getchar();
    return x;
}
void input()
{
    int i, x;
    N=read();
    for(i=1;i<=N;i++)
    {
        w[i]=read();
        x=read();
        adde(i,x), adde(x,i);
    }
}
void dp(int pos, int fa)
{
    int p;
    f[pos][1]=w[pos];
    for(p=head[pos];p;p=nex[p])
        if(to[p]!=fa and p!=cut and p!=(cut^1))
        {
            dp(to[p],pos);
            f[pos][0]+=max(f[to[p]][0],f[to[p]][1]);
            f[pos][1]+=f[to[p]][0];
        }
}
void dfs(int pos, int pre)
{
    int p;
    vis[pos]=1;
    for(p=head[pos];p;p=nex[p])
        if(p!=(pre^1))
        {
            if(!vis[to[p]])dfs(to[p],p);
            else u=pos, v=to[p];
        }
}
ll work(int pos)
{
    int i, p; ll ans=0;
    u=v=0;dfs(pos,0);
    for(p=head[u];to[p]!=v;p=nex[p]);cut=p;
    dp(u,0);ans=f[u][0];
    for(i=1;i<=N;i++)f[i][0]=f[i][1]=0;
    dp(v,0);ans=max(ans,f[v][0]);
    return ans;
}
int main()
{
    int i; ll ans=0;
    input();
    for(i=1;i<=N;i++)if(!vis[i])ans+=work(i);
    printf("%lld",ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值