题意:一个完全图,给定一棵生成树,树的边权为x,不在树上的边权为y,找出一条路经过所有点一次且总权值最小。
思路:当x>=y时,显然可以全部走y边,围着树的重心跑就行,但是星形图除外,最后要跑一次x边,特判以上就行。对于x<y,既然总的边数是n-1,那么肯定尽量多跑树上的边了,也就是树的最小路径覆盖问题,因为已经特判了星形图,所以不会存在“孤立根节点”的情况。因此可以通过
①树形dp,dp[i]表示以i为根的答案,那么i要么是非转折点,要么是转折点,分别用0和1表示,xjb转移就行。
②贪心,比较经典的东西了。
# include <bits/stdc++.h>
# define pb push_back
using namespace std;
typedef long long LL;
const LL inf = 0x3f3f3f3f3f3f3f3f;
const int maxn = 2e5+30;
LL dp[maxn][2];
vector<int>g[maxn];
int n, x, y, u, v;
void dfs(int cur, int pre)
{
LL sum = 0, son=0, cnt1=0, cnt2=0, imin1=inf, imin2=inf, flag=0;
for(int to:g[cur])
{
if(to == pre) continue;
dfs(to, cur);
if(g[to].size()>1) flag=1;
if(dp[to][0] <= dp[to][1])
{
sum += dp[to][0];
++cnt1;
}
else if(dp[to][0] >= dp[to][1])
{
sum += dp[to][1];
++cnt2;
if(dp[to][0]-dp[to][1] < imin1) imin2=imin1,imin1=dp[to][0]-dp[to][1];
else if(dp[to][0]-dp[to][1]<imin2) imin2=dp[to][0]-dp[to][1];
}
++son;
}
dp[cur][0] = dp[cur][1] = sum+son*y;
if(cnt1) dp[cur][0] = min(dp[cur][0], sum+x+(son-1)*y);
if(cnt2) dp[cur][0] = min(dp[cur][0], sum+imin1+x+(son-1)*y);
if(cnt1>1) dp[cur][1] = min(dp[cur][1], sum+2*x+(son-2)*y);
if(cnt2>1) dp[cur][1] = min(dp[cur][1], sum+imin1+imin2+2*x+(son-2)*y);
if(cnt1 && cnt2) dp[cur][1] = min(dp[cur][1], sum+imin1+2*x+(son-2)*y);
}
int main()
{
memset(dp, 0x3f, sizeof(dp));
LL ans = inf;
scanf("%d%d%d",&n,&x,&y);
for(int i=1; i<n; ++i)
{
scanf("%d%d",&u,&v);
g[u].pb(v);
g[v].pb(u);
}
if(x >= y)
{
for(int i=1; i<=n; ++i)
if(g[i].size()==n-1)
return 0*printf("%lld\n",1LL*(n-2)*y+x);
return 0*printf("%lld\n",1LL*(n-1)*y);
}
dfs(1, 0);
printf("%lld\n",min(dp[1][0],dp[1][1]));
return 0;
}
# include <bits/stdc++.h>
# define pb push_back
using namespace std;
typedef long long LL;
const int maxn = 2e5+30;
vector<int>g[maxn];
bool mark[maxn];
int v[maxn];
void dfs(int cur,int pre)
{
v[cur]=1;
int tot=0;
for(int to:g[cur])
{
if(to==pre)continue;
dfs(to, cur);
v[cur] += v[to];
if(!mark[to])tot++;
}
if(tot>=2) v[cur]-=2, mark[cur]=1;
else if(tot==1) --v[cur];
}
int main()
{
int n, x, y;
scanf("%d%d%d",&n,&x,&y);
for(int i=1, u, v; i<n; ++i)
{
scanf("%d%d",&u,&v);
g[u].pb(v);
g[v].pb(u);
}
if(x >= y)
{
for(int i=1; i<=n; ++i)
if(g[i].size()==n-1)
return 0*printf("%lld\n",1LL*(n-2)*y+x);
return 0*printf("%lld\n",1LL*(n-1)*y);
}
dfs(1, 0);
printf("%lld\n",1LL*(v[1]-1)*y+1LL*(n-v[1])*x);
return 0;
}