正题
这题想了半天打了个贪心一点分都拿不到...
其实这一题看到“任意乡村可以通过不超过40条道路到达首都。”所以说这个题的深度最大是40层,也就是说,每个乡村路径上的铁路和公路的总和一共也就40条。
所以我们要猜想它的时间复杂度。
20000*40*40=32000000.实际上是没有那么多的。
记忆化搜索就是我们所谓的树形DP。
我们想想,一个节点的两条边是不是只和子树内的叶子结点有关系,而跟外面的叶子结点没有关系。
那么我们用f[i][j][k]来表示第i个点,在上面未翻修j条公路和k条铁路后产生的最小价值。
f[i][j][k]显然等于选左边翻修,和选右边翻修的最小值。
反过来那么就是右边不翻修,左边不翻修。
所以,把状态不断往下传递求最小值即可。
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> using namespace std; int n; long long a[20010],b[20010],c[20010]; int son[40010][2]; long long f[30010][41][41]; long long dfs(int x,int y,int z){ if(son[x][0]==0) return c[x-(n-1)]*(a[x-(n-1)]+y)*(b[x-(n-1)]+z); if(f[x][y][z]!=f[20009][40][40]) return f[x][y][z]; return f[x][y][z]=min(dfs(son[x][0],y+1,z)+dfs(son[x][1],y,z),dfs(son[x][0],y,z)+dfs(son[x][1],y,z+1)); } int main(){ // freopen("road.in","r",stdin); // freopen("road.out","w",stdout); scanf("%d",&n); memset(f,63,sizeof(f)); for(int i=1;i<=n-1;i++){ int x,y; scanf("%d %d",&x,&y); if(x>0) son[i][0]=x; else son[i][0]=-x+n-1; if(y>0) son[i][1]=y; else son[i][1]=-y+n-1; } for(int i=1;i<=n;i++) scanf("%lld %lld %lld",&a[i],&b[i],&c[i]); printf("%lld",dfs(1,0,0)); }