BZOJ4987:Tree(树形DP)
Description
从前有棵树。
找出K个点A1,A2,…,Ak。
使得∑dis(AiAi+1),(1<=i<=K-1)最小。
Input
第一行两个正整数n,k,表示数的顶点数和需要选出的点个数。
接下来n-l行每行3个非负整数x,y,z,表示从存在一条从x到y权值为z的边。
I<=k<=n。
l<x,y<=n
1<=z<=10^5
n <= 3000
Output
一行一个整数,表示最小的距离和。
Sample Input
10 7
1 2 35129
2 3 42976
3 4 24497
2 5 83165
1 6 4748
5 7 38311
4 8 70052
3 9 3561
8 10 80238
1 2 35129
2 3 42976
3 4 24497
2 5 83165
1 6 4748
5 7 38311
4 8 70052
3 9 3561
8 10 80238
Sample Output
184524
Solution
贴一下神仙$beginend$的题解qwq
显然最优情况一定是原树的一棵大小为k的连通子树,然后直径上的边系数是1,其余边的系数是2。
那么我们可以进行树形dp,设f[i,j,0/1/2]表示以i为根的子树选了j个点,且直径的端点已经选了0/1/2个的最优方案。
那么我们可以进行树形dp,设f[i,j,0/1/2]表示以i为根的子树选了j个点,且直径的端点已经选了0/1/2个的最优方案。
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #define N (3009) 5 using namespace std; 6 7 struct Edge{int to,next,len;}edge[N<<1]; 8 int n,m,u,v,l,ans,INF,size[N],f[N][N][3],tmp[N][3]; 9 int head[N],num_edge; 10 11 void add(int u,int v,int l) 12 { 13 edge[++num_edge].to=v; 14 edge[num_edge].len=l; 15 edge[num_edge].next=head[u]; 16 head[u]=num_edge; 17 } 18 19 void Min(int &x,int y){x=min(x,y);} 20 21 void Dfs(int x,int fa) 22 { 23 size[x]=1; 24 for (int i=0;i<=n;i++) 25 for (int j=0;j<=2;j++) 26 f[x][i][j]=INF; 27 f[x][1][0]=f[x][1][1]=f[x][1][2]=0; 28 for (int i=head[x]; i; i=edge[i].next) 29 if (edge[i].to!=fa) 30 { 31 Dfs(edge[i].to,x); 32 for (int j=0; j<=size[x]+size[edge[i].to]; ++j) 33 tmp[j][0]=tmp[j][1]=tmp[j][2]=INF; 34 for (int j=0; j<=size[x]; ++j) 35 for (int k=0; k<=size[edge[i].to]; ++k) 36 { 37 int to=edge[i].to,len=edge[i].len; 38 Min(tmp[j+k][0],f[x][j][0]+f[to][k][0]+len*2); 39 Min(tmp[j+k][1],f[x][j][1]+f[to][k][0]+len*2); 40 Min(tmp[j+k][1],f[x][j][0]+f[to][k][1]+len); 41 Min(tmp[j+k][2],f[x][j][1]+f[to][k][1]+len); 42 Min(tmp[j+k][2],f[x][j][0]+f[to][k][2]+len*2); 43 Min(tmp[j+k][2],f[x][j][2]+f[to][k][0]+len*2); 44 } 45 size[x]+=size[edge[i].to]; 46 for (int j=0; j<=size[x]; ++j) 47 for (int k=0; k<=2; ++k) 48 f[x][j][k]=min(f[x][j][k],tmp[j][k]); 49 } 50 ans=min(ans,f[x][m][2]); 51 } 52 53 int main() 54 { 55 memset(&INF,0x3f,sizeof(INF)); 56 scanf("%d%d",&n,&m); 57 for (int i=1; i<=n-1; ++i) 58 { 59 scanf("%d%d%d",&u,&v,&l); 60 add(u,v,l); add(v,u,l); 61 } 62 ans=INF; Dfs(1,0); 63 printf("%d\n",ans); 64 }