正题
首先考虑x>=y的情况,先说结论:
当给出的树是一个菊花图时,就必须走一条树边,否则可以构造出一条路径使得其不经过树边。
菊花图的时候,如果从根开始走,那么只能通过一条树边来到达其他点,如果从叶子开始走,要走到根必须走一条树边。
若不是菊花图,则可以不经过树边。
首先考虑一个层数>=4的一张图。
每一层缩成一个点。(因为到达这一层的任意一个点就可以到达这一层的另外一些点)
那么就变成一条长>=4的一条链,从上往下选这个点为起始点,然后依次经过n,1,n-1,2,...,若n为奇数,那么结尾就在起始点旁边,若n为偶数,那么结尾就为
这个点。在走的过程中,每一步都跳到了不与自己相邻的一个点。不太懂的可以画图验证。
讨论一个层数=3的树,若根的儿子=1,那么可以转化为一棵层数为2的树(菊花图)
否则可以转化为一棵层数为4的树,取一个叶子当根即可。
那么我们就证明了这个定理,即使不是那么的严谨。
接着讨论x<y的情况。
那么相当于求最小树上路径覆盖。
这个东西在DAG上可以直接使用网络流来求解,在无向图上比较困难。
树这种无向图有什么特殊情况呢?
我们直接设表示覆盖完x这个子树,向上不延伸/延伸一条路径的最小路径覆盖。
然后转移具体可以看一下代码,在这里就不说了,还是比较好想的。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
using namespace std;
const int N=200010;
int n,a,b;
struct edge{
int y,next;
}s[N<<1];
int in[N];
int f[N][2],first[N],len;
void ins(int x,int y){
s[++len]=(edge){y,first[x]};first[x]=len;in[x]++;
s[++len]=(edge){x,first[y]};first[y]=len;in[y]++;
}
void dfs(int x,int fa){
int mmin=1e9,cmin=1e9;
for(int i=first[x];i!=0;i=s[i].next) if(s[i].y!=fa){
int y=s[i].y;
dfs(y,x);
f[x][0]+=f[y][0];
if(f[y][1]-f[y][0]<mmin) cmin=mmin,mmin=f[y][1]-f[y][0];
else if(f[y][1]-f[y][0]<cmin) cmin=f[y][1]-f[y][0];
f[x][1]+=f[y][0];
}
if(mmin==1e9) {f[x][0]=f[x][1]=1;return ;}
f[x][1]+=min(1,mmin);
if(cmin==1e9) {f[x][0]=f[x][1];return ;}
f[x][0]+=min(1,mmin+cmin-1);
}
int main(){
scanf("%d %d %d",&n,&a,&b);
int x,y;
for(int i=1;i<n;i++) scanf("%d %d",&x,&y),ins(x,y);
if(a>=b){
int mmax=0;
for(int i=1;i<=n;i++) mmax=max(mmax,in[i]);
if(mmax==n-1) printf("%lld",1ll*b*(n-2)+a);
else printf("%lld",1ll*b*(n-1));
return 0;
}
dfs(1,0);
printf("%lld",1ll*(f[1][0]-1)*b+1ll*(n-f[1][0])*a);
}
本文探讨了在树形结构中寻找最小路径覆盖的问题,针对x大于等于y和x小于y两种情况,分别提出了不同的解决方案。对于x大于等于y的情况,文章详细分析了如何在不同类型的树中找到至少包含一条树边的路径;而对于x小于y的情况,则将其转化为最小树上路径覆盖问题,并介绍了如何使用动态规划的方法进行求解。
193

被折叠的 条评论
为什么被折叠?



