bzoj4987 Tree 树上背包
发布时间:2020-12-13 21:28:49 所属栏目:PHP教程 来源:网络整理
导读:题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4987 题解 一道还不错的题咯。 很容易发现一个结论:这 (k) 个点构成的一定是一个连通块,并且走的时候应该是按照某种类似于 dfs 的遍历方式连续走的。 可以发现,最终答案应该有:从根的某个子
题目传送门https://lydsy.com/JudgeOnline/problem.php?id=4987 题解一道还不错的题咯。 很容易发现一个结论:这 (k) 个点构成的一定是一个连通块,并且走的时候应该是按照某种类似于 dfs 的遍历方式连续走的。 可以发现,最终答案应该有:从根的某个子树走出来,到某个子树中去的这样的情况,也有可能是从根到某个子树中去的情况;同时,过程中会用到从根到子树中走一遍再回到根的情况。这三种情况都需要考虑。 于是进行树形 dp,令 (dp[x][i][0/1/2]) 表示以 (x) 为根的子树中,选择了 (i) 个点,情况为从根到子树中走一遍再回到根/从根到某个子树中去(等同于从某个子树到根)/从根的某个子树走出来,到某个子树中去这三种情况,转移的时候,第二维直接背包合并,第三维是这样的:(0+0to 0,0+1to 1,1+0to 1,0+2to 2,1+1to 2,2+0to 2)。 代码如下,时间复杂度为一般的背包合并 (O(nk))。 #include<bits/stdc++.h> #define fec(i,x,y) (int i = head[x],y = g[i].to; i; i = g[i].ne,y = g[i].to) #define dbg(...) fprintf(stderr,__VA_ARGS__) #define File(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout) #define fi first #define se second #define pb push_back template<typename A,typename B> inline char smax(A &a,const B &b) {return a < b ? a = b,1 : 0;} template<typename A,typename B> inline char smin(A &a,const B &b) {return b < a ? a = b,1 : 0;} typedef long long ll; typedef unsigned long long ull; typedef std::pair<int,int> pii; template<typename I> inline void read(I &x) { int f = 0,c; while (!isdigit(c = getchar())) c == '-' ? f = 1 : 0; x = c & 15; while (isdigit(c = getchar())) x = (x << 1) + (x << 3) + (c & 15); f ? x = -x : 0; } const int N = 3000 + 7; const int INF = 0x3f3f3f3f; int n,m,ans; int dp[N][N][3],siz[N]; struct Edge { int to,ne,w; } g[N << 1]; int head[N],tot; inline void addedge(int x,int y,int z) { g[++tot].to = y,g[tot].w = z,g[tot].ne = head[x],head[x] = tot; } inline void adde(int x,int z) { addedge(x,y,z),addedge(y,z); } inline void dfs(int x,int fa = 0) { dp[x][1][0] = dp[x][1][1] = 0; siz[x] = 1; for fec(i,y) if (y != fa) { dfs(y,x); int w = g[i].w; for (int i = std::min(m,siz[x]); i; --i) for (int j = 1; j <= std::min(m,siz[y]); ++j) { smin(dp[x][i + j][0],dp[x][i][0] + dp[y][j][0] + w * 2); smin(dp[x][i + j][1],dp[x][i][0] + dp[y][j][1] + w); smin(dp[x][i + j][1],dp[x][i][1] + dp[y][j][0] + w * 2); smin(dp[x][i + j][2],dp[x][i][0] + dp[y][j][2] + w * 2); smin(dp[x][i + j][2],dp[x][i][1] + dp[y][j][1] + w); smin(dp[x][i + j][2],dp[x][i][2] + dp[y][j][0] + w * 2); } siz[x] += siz[y]; } smin(ans,dp[x][m][0]),smin(ans,dp[x][m][1]),dp[x][m][2]); // dbg("x = %d: ",x); // for (int i = 1; i <= m; ++i) dbg("%d:(%d,%d,%d) ",i,dp[x][i][0],dp[x][i][1],dp[x][i][2]); // dbg("n"); } inline void work() { memset(dp,0x3f,sizeof(dp)); ans = INF; dfs(1); printf("%dn",ans); } inline void init() { read(n),read(m); int x,z; for (int i = 1; i < n; ++i) read(x),read(y),read(z),adde(x,z); } int main() { #ifdef hzhkk freopen("hkk.in",stdin); #endif init(); work(); fclose(stdin),fclose(stdout); return 0; } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |