树形dp,在树结构上,求最优值,求方案等dp问题,就可以考虑是树形dp
试了好几遍才a。。
方法很多,来我的
g【i】:一个人走完子树的最短dis
sum【i】:子树的总边距离乘二,就是一个人走完回到根的路程
f【i】【0】:表示两者在同一个子树中的最短距离
f【i】【1】:表示两者在不同子树中的最短距离
感觉状态的表难想,细节难处理。
这里的状态,我感觉,是根据题目的性质,分情况(因为只有可能两人在同一个子树或不同的子树两种情况),分情况来表示状态,在为了这两个状态才来维护一些其他的东西。
转移实际上推一推就出来了
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<cstdlib> using namespace std; const int inf=0x3f3f3f3f; int f[100010][2],g[100010],sum[100010]; int n,s,fa[100010]; int head[100010],tot; struct aa { int to,pre,dis; }edge[100010]; void addedge(int x,int y,int z) { edge[++tot].to=y;edge[tot].dis=z;edge[tot].pre=head[x];head[x]=tot; } void dfs(int u) { int fi=0,se=0; for (int i=head[u];i;i=edge[i].pre) { int v=edge[i].to; if (fa[u]==v) continue; sum[v]=edge[i].dis*2; g[v]=edge[i].dis; fa[v]=u; dfs(v); if (sum[v]-g[v]>fi) se=fi,fi=sum[v]-g[v]; else if (sum[v]-g[v]>se) se=sum[v]-g[v];//注意如果只有1个孩子怎么办 sum[u]+=sum[v]; } int disfa=g[u]; f[u][1]=sum[u]-fi-se;//注意,两个人如果在u这个子树中,那么disfa就是走了两次,我就是在这里错了 g[u]=sum[u]-fi-disfa; f[u][0]=inf; for (int i=head[u];i;i=edge[i].pre) { int v=edge[i].to; if (v==fa[u]) continue; f[u][0]=min(min(f[v][0],f[v][1])+sum[u]-sum[v],f[u][0]); } if (f[u][0]==inf) f[u][0]=sum[u]; } int main() { scanf("%d%d",&n,&s); int x,y,z; for (int i=1;i<n;i++) { scanf("%d%d%d",&x,&y,&z); addedge(x,y,z); addedge(y,x,z); } dfs(s); printf("%d\n",min(f[s][1],f[s][0])); return 0; }