最后基本靠自己的思路秒了这个题吧
先排除不合法情况
一个K一个M十分恶心
然后结合不合法仔细想一想只有m==2的时候小头才会产生花费
所以问题就变成选择k个点 花费是所有两个端点都选择的边的边权 求最小花费
按照套路先考虑dp[i][j][0]表示以i为根处理完当前子树 选j个点 0/1表示是否选择根
所以就可以转移
注意一棵子树dp的时候滚动数组不要滚错了 实在不行(像我)开一个tmp代替滚动也行
(memcpy真快)
Time cost: 65min
Code:
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cmath> 5 #include<queue> 6 #include<iostream> 7 #define ms(a,b) memset(a,b,sizeof a) 8 #define rep(i,a,n) for(int i = a;i <= n;i++) 9 #define per(i,n,a) for(int i = n;i >= a;i--) 10 #define inf 2147483647 11 using namespace std; 12 typedef long long ll; 13 typedef double D; 14 #define eps 1e-8 15 ll read() { 16 ll as = 0,fu = 1; 17 char c = getchar(); 18 while(c < '0' || c > '9') { 19 if(c == '-') fu = -1; 20 c = getchar(); 21 } 22 while(c >= '0' && c <= '9') { 23 as = as * 10 + c - '0'; 24 c = getchar(); 25 } 26 return as * fu; 27 } 28 //head 29 const int N = 305; 30 int n,m,K; 31 int head[N],nxt[N<<1],mo[N<<1],cst[N<<1],cnt; 32 void _add(int x,int y,int w) { 33 mo[++cnt] = y; 34 cst[cnt] = w; 35 nxt[cnt] = head[x]; 36 head[x] = cnt; 37 } 38 void add(int x,int y) { 39 int w = read(); 40 _add(x,y,w),_add(y,x,w); 41 } 42 43 int dp[N][N][2]; 44 int tmp[N][2]; 45 void dfs(int x,int f) { 46 dp[x][0][0] = dp[x][1][1] = 0; 47 for(int i = head[x];i;i = nxt[i]) { 48 int sn = mo[i]; 49 if(sn == f) continue; 50 dfs(sn,x); 51 memcpy(tmp,dp[x],sizeof(tmp)); 52 ms(dp[x],63); 53 rep(j,0,K) rep(t,0,j) { 54 dp[x][j][0] = min(dp[x][j][0],dp[sn][t][0] + tmp[j-t][0] + (m == 2) * cst[i]); 55 dp[x][j][0] = min(dp[x][j][0],dp[sn][t][1] + tmp[j-t][0]); 56 dp[x][j][1] = min(dp[x][j][1],dp[sn][t][1] + tmp[j-t][1] + cst[i]); 57 dp[x][j][1] = min(dp[x][j][1],dp[sn][t][0] + tmp[j-t][1]); 58 } 59 } 60 } 61 62 int main() { 63 n = read(),m = read(),K = read(); 64 if(n-m-K+1 < 0) { 65 puts("-1"); 66 return 0; 67 } 68 rep(i,2,n) add(read(),read()); 69 ms(dp,63); 70 dfs(1,1); 71 printf("%d ",dp[1][K][1]); 72 return 0; 73 }