1912: [Apio2010]patrol 巡逻

本文介绍了一种使用树形DP解决特定图论问题的方法,即在一棵树中通过增加一条或多条边来求解遍历所有节点后返回起点的最小路径长度。文章详细解析了针对不同情况的算法实现,并分享了作者的独特见解。

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

题目链接

题目大意:给一棵树,求加k条边之后,从1号点遍历每个点之后再回到1号点的最小距离和。k=1或2

题解: 12(n1)ans=2(n1)

k=1,求出树上最长链,把最长链首尾相连, ans=anslen+1

k=2,将第一次选取的最长链边权值置为-1,再重复操作1

如果两次走到重复的边呢?第一次算这条边的时候加了1,第二次的时候加的是-1,这条边没有贡献,相当于是把两条交错的链变成了两条分开的链,Orz

因为有负边权,这题没法用bfs/dfs找直径,需要树形dp

我的收获:神奇的消除重复影响的方法

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int M=100005;

int n,t,ans,c,k;
int rt,tia;
int head[M],dis[M],fa[M],s1[M],s2[M];

struct edge{int to,val,nex;}e[M*4];

void add(int u,int v){e[t]=(edge){v,1,head[u]};head[u]=t++;}

int dfs(int x,int fa)
{
    int fr=0,se=0;
    for(int i=head[x];i!=-1;i=e[i].nex){
        int v=e[i].to;
        if(v==fa) continue;
        int l=e[i].val+dfs(v,x);
        if(l>fr) se=fr,fr=l,s2[x]=s1[x],s1[x]=i;
        else if(l>se) se=l,s2[x]=i;
    }
    if(fr+se>tia) tia=fr+se,rt=x;
    return fr;
}

void work()
{
    dfs(1,0);
    ans=2*(n-1)-tia+1;
    if(k==1) {printf("%d\n",ans);return ;}
    tia=0;
    for(int i=s1[rt];i;i=s1[e[i].to]) e[i].val=e[i^1].val=-1;
    for(int i=s2[rt];i;i=s1[e[i].to]) e[i].val=e[i^1].val=-1;
    dfs(1,0);ans=ans-tia+1;
    cout<<ans<<endl;
}

void init()
{
    int x,y;
    cin>>n>>k;t=0;memset(head,-1,sizeof(head));
    for(int i=1;i<n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);
}

int main()
{
    init();
    work();
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值