【BZOJ1812】riv(多叉树转二叉树,树形DP)
题意:给定一棵树,每个点有权值,每条边有边权(单向边)。你可以选取K个黑点,使得从每个点移动到距离他最近的黑点的花费(距离*点权)的总和最小。
n<=100 k<=50 w[i],a[i]<=10000
思路:见IOI2005龙凡解题报告
为什么要多叉转二叉?因为假设点U被选,这个被选点只会对U自己的儿子有影响,对U的兄弟并没有影响
dp[i,j,k]表示以i为根的子树,建j个节点,离i最近的被选点是k时的最小总和
\[ dp[i,j,k]=min\begin{cases} dp[l[i],t,k]+dp[r[i],j-t,k]+(dis[i]-dis[k])*a[i]\\dp[l[i],t,i]+dp[r[i],j-t-1,k] \end{cases} \]
1 var dp:array[1..200,0..60,1..200]of longint; 2 head,vet,next,len,l,r,tree,a,dis:array[1..1000]of longint; 3 n,m,i,x,y,tot:longint; 4 5 procedure add(a,b,c:longint); 6 begin 7 inc(tot); 8 next[tot]:=head[a]; 9 vet[tot]:=b; 10 len[tot]:=c; 11 head[a]:=tot; 12 end; 13 14 procedure dfs(u:longint); 15 var e,v:longint; 16 begin 17 e:=head[u]; 18 while e<>0 do 19 begin 20 v:=vet[e]; 21 dis[v]:=dis[u]+len[e]; 22 dfs(v); 23 e:=next[e]; 24 end; 25 end; 26 27 function min(x,y:longint):longint; 28 begin 29 if x<y then exit(x); 30 exit(y); 31 end; 32 33 function ask(u,i,k:longint):longint; 34 var ans,j:longint; 35 begin 36 if dp[u,i,k]<maxlongint div 3 then exit(dp[u,i,k]); 37 dp[u,i,k]:=maxlongint div 3; 38 for j:=0 to i do 39 begin 40 ans:=0; 41 if l[u]>0 then ans:=ans+ask(l[u],j,k); 42 if r[u]>0 then ans:=ans+ask(r[u],i-j,k); 43 dp[u,i,k]:=min(dp[u,i,k],ans+(dis[u]-dis[k])*a[u]); 44 if i-j-1>=0 then 45 begin 46 ans:=0; 47 if l[u]>0 then ans:=ans+ask(l[u],j,u); 48 if r[u]>0 then ans:=ans+ask(r[u],i-j-1,k); 49 dp[u,i,k]:=min(dp[u,i,k],ans); 50 end; 51 end; 52 //writeln(u-1,' ',i,' ',k-1); 53 exit(dp[u,i,k]); 54 end; 55 56 begin 57 assign(input,'bzoj1812.in'); reset(input); 58 assign(output,'bzoj1812.out'); rewrite(output); 59 readln(n,m); 60 inc(n); 61 for i:=2 to n do 62 begin 63 read(a[i],x,y); 64 inc(x); 65 if tree[x]=0 then begin l[x]:=i; tree[x]:=i; end 66 else begin r[tree[x]]:=i; tree[x]:=i; end; 67 add(x,i,y); 68 end; 69 dfs(1); 70 fillchar(dp,sizeof(dp),$7f); 71 writeln(ask(1,m,1)); 72 close(input); 73 close(output); 74 end.
null