题目大意:不告诉你QAQ
树形DP:
发现子树内最多存在一个不能和其他关键点联通的点
如果有两个以上,就需要砍掉边使他们两个不联通,剩下一个
f[i][1]表示子树内有一个不能和其他关键点联通的点
f[i][0]表示没有
转移方程看代码啦
注意f[i][1]要从f[i][0]转移过来
#include<cstdio>
#include<cstring>
const int N=1e5+7;
struct node
{
int to,next,c;
}e[N*2];
int first[N],cnt,visit[N];
void insert(int u,int v,int c)
{
e[++cnt]=(node){v,first[u],c};first[u]=cnt;
e[++cnt]=(node){u,first[v],c};first[v]=cnt;
}
int a[N];
long long int f[N][2];
inline long long int min(long long int a,long long int b)
{
return a<b?a:b;
}
void dfs(int x)
{
visit[x]=1;
for(int k=first[x];k;k=e[k].next)
if(!visit[e[k].to])
{
dfs(e[k].to);
f[x][1]=min(f[x][0]+f[e[k].to][1],f[x][1]+min(f[e[k].to][1]+e[k].c,f[e[k].to][0]));
f[x][0]=f[x][0]+min(f[e[k].to][1]+e[k].c,f[e[k].to][0]);
}
}
int main()
{
freopen("attack.in","r",stdin);
freopen("attack.out","w",stdout);
int n,k;
scanf("%d %d",&n,&k);
int x;
for(int i=1;i<=k;i++) scanf("%d",&x),f[x+1][0]=2*1e15+7;
for(int i=1;i<n;i++)
{
int u,v,c;
scanf("%d %d %d",&u,&v,&c);insert(u+1,v+1,c);
}
dfs(1);
printf("%lld\n",min(f[1][0],f[1][1]));
fclose(stdin);
fclose(stdout);
return 0;
}
当然,还有并查集的写法: