洛谷P3931 SAC E#1 - 一道难题 Tree
思路:
树形dp。
设
d
p
[
i
]
dp[i]
dp[i]表示割掉根节点为
i
i
i的子树的叶节点的最小权值和。
显然,我们要使根和一个根结点为
i
i
i的子树的叶节点不连通,则要么割掉
i
i
i和父亲结点的那条边,要么割掉
i
i
i和所有的儿子结点的权值和。
即:
d
p
[
i
]
=
m
i
n
(
e
[
f
a
−
>
i
]
,
d
p
[
s
o
n
1
]
+
d
p
[
s
o
n
2
]
+
⋯
+
d
p
[
s
o
n
n
]
)
dp[i]=min(e[fa->i],dp[son_1]+dp[son_2]+\cdots+dp[son_n])
dp[i]=min(e[fa−>i],dp[son1]+dp[son2]+⋯+dp[sonn])
最后输出
d
p
[
r
o
o
t
]
dp[root]
dp[root]就行了。
代码:
#include<bits/stdc++.h>
#define pii pair<int,int>
#define ll long long
#define cl(x,y) memset(x,y,sizeof(x))
#define ct cerr<<"Time elapsed:"<<1.0*clock()/CLOCKS_PER_SEC<<"s.\n";
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define lson x<<1,l,mid
#define rson x<<1|1,mid+1,r
#define INF 1e18
const int N=1e6+10;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const double eps=1e-8;
const double pi=acos(-1);
using namespace std;
struct edge
{
int u,v,w;
}e[N];
int head[N]={0},len=0,dp[N]={0};
void add(int u,int v,int w)
{
e[++len]={head[u],v,w};
head[u]=len;
}
void dfs(int u,int fa,int s)
{
int sum=0,i;
dp[u]=s;
for(i=head[u];i;i=e[i].u)
{
int v=e[i].v,w=e[i].w;
if(v==fa)
continue;
dfs(v,u,w);
sum+=dp[v];
}
if(sum)
dp[u]=min(dp[u],sum);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n,i,root;
cin>>n>>root;
for(i=1;i<n;i++)
{
int u,v,w;
cin>>u>>v>>w;
add(u,v,w);
add(v,u,w);
}
dfs(root,0,inf);
cout<<dp[root]<<endl;
return 0;
}