洛谷 P4362 [NOI2002]贪吃的九头龙
https://www.luogu.org/problemnew/show/P4362
首先有个很显然的dp:ans[i][j][k]表示i节点用j号头,i节点为根的子树中共有k个点用大头时i节点为根的子树内的最小答案
可以发现复杂度不太对。。
研究一下,可以发现:如果没有大头的限制,且有>=2个头,那么答案一定是0
毕竟,只要把所有节点按深度分类,同一深度的用同一种头,深度相差1的任意两类用不同种头,那么答案就是0了
也可以发现:有了大头的限制,且有>=3个头,那么确定每个节点是否用大头之后,一定可以确定一种方案(即确定所有不是大头的节点具体用哪个头),并保证任意两个不是大头的节点间不产生贡献(只要把所有不是大头的节点按深度分类就行了)
那么,状态简化为:ans[i][j][k]表示i号节点是/否用大头(由k决定),i号节点为根的子树中有j个点用大头时,i号节点为根的子树中的最小答案
可以做了。。如果有>=3个头,照上面的做dp;如果只有2个头,与>=3个头时的区别仅仅是任意两个不是大头的节点间一定产生贡献,稍微改一下就行
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<vector> 5 using namespace std; 6 #define fi first 7 #define se second 8 #define mp make_pair 9 #define pb push_back 10 typedef long long ll; 11 typedef unsigned long long ull; 12 typedef pair<int,int> pii; 13 struct E 14 { 15 int to,nxt,d; 16 }e[610]; 17 int f1[310],ne; 18 int n,m,K; 19 int an[310][310][2]; 20 bool fl1; 21 void dfs(int u,int fa) 22 { 23 int i,j,k,v,t1,t2; 24 an[u][1][1]=an[u][0][0]=0; 25 for(k=f1[u];k;k=e[k].nxt) 26 { 27 v=e[k].to; 28 if(v!=fa) 29 { 30 dfs(v,u); 31 for(i=K;i>=0;i--) 32 { 33 t1=t2=0x3f3f3f3f; 34 for(j=0;j<=i;j++) 35 { 36 t1=min(t1,min( 37 an[v][j][0]+an[u][i-j][0]+e[k].d*fl1, 38 an[v][j][1]+an[u][i-j][0])); 39 t2=min(t2,min( 40 an[v][j][0]+an[u][i-j][1], 41 an[v][j][1]+an[u][i-j][1]+e[k].d)); 42 } 43 an[u][i][0]=t1; 44 an[u][i][1]=t2; 45 } 46 } 47 } 48 } 49 int main() 50 { 51 int i,a,b,c; 52 memset(an,1,sizeof(an)); 53 scanf("%d%d%d",&n,&m,&K); 54 if(n-K<m-1) 55 { 56 puts("-1"); 57 return 0; 58 } 59 for(i=1;i<n;i++) 60 { 61 scanf("%d%d%d",&a,&b,&c); 62 e[++ne].to=b;e[ne].nxt=f1[a];f1[a]=ne;e[ne].d=c; 63 e[++ne].to=a;e[ne].nxt=f1[b];f1[b]=ne;e[ne].d=c; 64 } 65 fl1=(m==2); 66 dfs(1,0); 67 printf("%d",an[1][K][1]); 68 return 0; 69 }