P1272 重建道路
考察:树形dp
推dp转移方程的时候,总是忘记f数组原来定义的含义...初始化也可以帮助推出dp数组.
思路:
f[u][j] 表示以u为根的子树中,保留j个点最少的剪枝数.初始化f[u][1] = son[u].这样初始化一开始点都是独立的,通过下面的转移方程将它们连起来.
那么dp转移方程 f[u][j] = min(f[u][j-k]+f[v][k]-1,f[u][j]).为什么-1呢当j = 2时,f[u][2] = f[u][1]+f[v][1] f[u][1]被初始化为全部的子节点数,我们还要将u-v的边减去.
最后的ans是枚举子树根节点,如果当前点是1 ans = min(ans,f[u][p]) 如果不是 ans = min(ans,f[u][p]+1).
1 #include <iostream> 2 #include <cstring> 3 using namespace std; 4 const int N = 160,INF = 0x3f3f3f3f; 5 int n,p,idx,h[N],son[N],f[N][N],ans = INF; 6 struct Road{ 7 int fr,to,ne; 8 }road[N]; 9 void add(int a,int b) 10 { 11 road[idx].fr = a,road[idx].to = b,road[idx].ne = h[a],h[a] = idx++; 12 } 13 void dfs(int u) 14 { 15 f[u][1] = son[u]; 16 for(int i=h[u];i!=-1;i=road[i].ne) 17 { 18 int v = road[i].to; 19 dfs(v); 20 for(int j=p;j>=1;j--) 21 for(int k=0;k<j;k++) 22 f[u][j] = min(f[v][k]+f[u][j-k]-1,f[u][j]); 23 } 24 if(u!=1) ans = min(ans,f[u][p]+1); 25 else ans = min(ans,f[u][p]); 26 } 27 int main() 28 { 29 scanf("%d%d",&n,&p); 30 memset(h,-1,sizeof h); 31 for(int i=1;i<n;i++) 32 { 33 int a,b; scanf("%d%d",&a,&b); 34 add(a,b); 35 son[a]++; 36 } 37 memset(f,0x3f,sizeof f); 38 dfs(1); 39 printf("%d\n",ans); 40 return 0; 41 }