APIO2010巡逻 分类讨论+树的直径

APIO2010巡逻

Solution:

① K=0:

一棵树,每条边必须经过两次,ans=2*(n-1)。

② K=1:

考虑加边后形成的环。

对于环上的边我们发现能且仅仅经过一次,非环上的边不变。

因此,ans=2*(n-1)-环长。

什么时候答案最小?

显然就是当新加入的边连向树的直径两端点时,环最长,答案也最小。

③ K=2:

讨论一下两环的位置情况:

<1>、两环不相交:那么由②可知答案继续减小,答案怎么求在下面。

<2>、两环相交:为了遍历完所有的边,那么重复的部分等价于又需要经过两次,所以答案增加。

具体答案怎么多少,怎么求???

先给出算法:把直径(长度为L1)求出来后,再把直径上的边全部取负,再求一遍直径(长度为L2),

答案就是 ans=2*(n-1)-(L1-1)-(L2-1) !!!

最巧妙的一步就是把直径给取负!

可以发现,

如果得到的新的直径 经过了原来的直径,就会对应减少相交部分的长度,对应情况<2>。否则对应情况<1>。

另:这个题还有一个很有意义的就是充分考察了对直径求法的运用:

两遍BFS(DFS)可以处理出直径长度和直径的相关信息,因此第一遍必须用这种方法求。

树形DP求直径则可以处理边权为负的情况,所以第二遍又必须用这种方法求。

Code↓:

#include <bits/stdc++.h>
#define RG register
#define IL inline
#define LL long long
#define DB double
using namespace std;

IL int gi() {
    char ch=getchar(); int x=0,q=0;
    while(ch<'0'||ch>'9') q=ch=='-'?1:q,ch=getchar();
    while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    return q?-x:x;
}

const int N=1e5+10;
const int INF=0x3f3f3f3f;

int n,K,L1,L2,tot,head[N],fa[N],tag[N],dis[N];

struct EDGE{int next,to;}e[N<<1];
IL void make(int a,int b) {
    e[++tot]=(EDGE){head[a],b},head[a]=tot;
    e[++tot]=(EDGE){head[b],a},head[b]=tot;
}

void dfs(int x,int fx) {
    RG int i,y;
    for (i=head[x],fa[x]=fx;i;i=e[i].next)
        if ((y=e[i].to)!=fx)
            dis[y]=dis[x]+1,dfs(y,x);
}

void Tree_DP(int x,int fx) {
    RG int i,y,ver;
    for (i=head[x];i;i=e[i].next)
        if ((y=e[i].to)!=fx) {
            Tree_DP(y,x),ver=(tag[x]&&tag[y])?-1:1;
            L2=max(L2,dis[x]+dis[y]+ver);
            dis[x]=max(dis[x],dis[y]+ver);
        }
}

int main()
{
    RG int i,x,y,S,s,Max;
    n=gi(),K=gi();
    for (i=1;i<n;++i) x=gi(),y=gi(),make(x,y);
    for (i=2,S=1,Max=0,dfs(1,0);i<=n;++i)
        if (dis[i]>Max) Max=dis[i],S=i;
    dis[S]=0,dfs(S,0);
    for (i=1,s=S;i<=n;++i)
        if (dis[i]>L1) L1=dis[i],s=i;
    if (K==1) printf("%d\n",2*(n-1)-(L1-1));
    else {
        while (s) tag[s]=1,s=fa[s];
        memset(dis,0,sizeof(dis));
        Tree_DP(1,0);
        printf("%d\n",2*(n-1)-(L1-1)-(L2-1));   
    }
    return 0;
}

The End

转载于:https://www.cnblogs.com/Bhllx/p/10616465.html

springboot052基于Springboot+Vue旅游管理系统毕业源码案例设计 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值