[树形DP]JZOJ 5906 传送门
分析
我们知道,一条边至少被经过1次
第二,传送门肯定是从下往上传送的
如果设f[i][0/1]表示走完了以i为根的子树在子树内用/没用传送门的时间,f[i][0]显而易见就等于∑f[son][0]+w[i to son]*2
然后f[i][1]则要额外考虑一下,首先对于不是在i处使用传送门的情况:
f[i][1]+=f[son][1]+w[i to son]*2
在i处使用传送门的情况:
f[i][1]+=f[son][0]+w[i to son]-lengthofline[son]
最后那个意思是以son为起点的最长链的长度,这是显然的,因为使用传送门是可以减少回来的时间
然后综合一下:
f[i][1]+=min(1,2)
而且为了时间最少,答案一定是使用过传送门的,所以ans=f[root][1]
#include <iostream> #include <cstdio> using namespace std; typedef long long ll; const int N=1e6+10; struct Edge { int u,v,nx; ll w; }g[2*N]; int cnt,list[N]; ll f[N][2],l[N]; int n; void Add(int u,int v,ll w) { g[++cnt].u=u;g[cnt].v=v;g[cnt].w=w;g[cnt].nx=list[u];list[u]=cnt; } void Dfs(int u,int fa) { for (int i=list[u];i;i=g[i].nx) if (g[i].v!=fa) { Dfs(g[i].v,u); l[u]=max(l[u],l[g[i].v]+g[i].w); f[u][0]+=f[g[i].v][0]+g[i].w*2; f[u][1]+=min(f[g[i].v][1]+g[i].w*2,f[g[i].v][0]+g[i].w-l[g[i].v]); } } int main() { freopen("portal.in","r",stdin); freopen("portal.out","w",stdout); scanf("%d",&n); for (int i=1;i<n;i++) { int u,v;ll w; scanf("%d%d%lld",&u,&v,&w); Add(u,v,w);Add(v,u,w); } Dfs(1,-1); printf("%lld",f[1][1]); fclose(stdin);fclose(stdout); }
在日渐沉没的世界里,我发现了你。