bzoj 4987: Tree
4987: Tree
Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 51 Solved: 27
[Submit][Status][Discuss]
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
#include<iostream> #include<cstdio> #include<cstring> #define maxn 3010 using namespace std; int head[maxn],num,sz[maxn],f[maxn][maxn][3]; struct node{int to,pre,v;}e[maxn*2]; void Insert(int from,int to,int v){ e[++num].to=to; e[num].v=v; e[num].pre=head[from]; head[from]=num; } void dfs(int x,int father){ sz[x]=1;f[x][0][0]=f[x][0][1]=0; for(int i=head[x];i;i=e[i].pre){ int to=e[i].to; if(to==father)continue; dfs(to,x); for(int j=sz[x]-1;j>=0;j--) for(int k=sz[to]-1;k>=0;k--) for(int l=2;l>=0;l--) for(int m=l;m>=0;m--) f[x][j+k+1][l]=min(f[x][j+k+1][l],f[x][j][l-m]+f[to][k][m]+e[i].v*(2-(m&1))); sz[x]+=sz[to]; } } int main(){ int n,k,x,y,z,ans=1<<30; scanf("%d%d",&n,&k); for(int i=1;i<n;i++){ scanf("%d%d%d",&x,&y,&z); Insert(x,y,z);Insert(y,x,z); } memset(f,0x3f,sizeof(f)); dfs(1,0); for(int i=1;i<=n;i++) for(int j=0;j<=2;j++) ans=min(ans,f[i][k-1][j]); printf("%d",ans); return 0; }