Time Limit: 1000MS | Memory Limit: 30000K | |
Total Submissions: 8479 | Accepted: 3795 |
Description
Input
Output
Sample Input
11 6 1 2 1 3 1 4 1 5 2 6 2 7 2 8 4 9 4 10 4 11
Sample Output
2
Hint
[A subtree with nodes (1, 2, 3, 6, 7, 8) will become isolated if roads 1-4 and 1-5 are destroyed.]
给定一棵树,求分离出一颗p个节点的子树所需要的最少的破坏边数,
乍一看,没思路,想了好久,总算是理解了,一个题目可能有多种思考的方式,总要找到符合自己的思考方式,
用dp[i][j]表示分离出以i为根,j为大小的子树,显然dp[i][1]为i节点度数,然后就是背包合并的过程,每两个连通块合并时,
需要减去2,就是多统计的2,树形dp轻松搞定。
代码:
/* *********************************************** Author :xianxingwuguan Created Time :2014-2-4 16:25:33 File Name :1.cpp ************************************************ */ #pragma comment(linker, "/STACK:102400000,102400000") #include <stdio.h> #include <iostream> #include <algorithm> #include <sstream> #include <stdlib.h> #include <string.h> #include <limits.h> #include <string> #include <time.h> #include <math.h> #include <queue> #include <stack> #include <set> #include <map> using namespace std; #define INF 0x3f3f3f3f #define eps 1e-8 #define pi acos(-1.0) typedef long long ll; const int maxn=160; int head[maxn],tol,deg[maxn],dp[maxn][maxn],m; struct node{ int next,to; }edge[2*maxn]; void add(int u,int v){ edge[tol].to=v; edge[tol].next=head[u]; head[u]=tol++; } void dfs(int u,int fa){ dp[u][1]=deg[u]; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].to; if(v==fa)continue; dfs(v,u); for(int j=m;j>1;j--) for(int k=1;k<j;k++) dp[u][j]=min(dp[u][j],dp[u][j-k]+dp[v][k]-2); } } int main() { //freopen("data.in","r",stdin); //freopen("data.out","w",stdout); int i,j,k,n; while(~scanf("%d%d",&n,&m)){ memset(head,-1,sizeof(head)); tol=0; memset(deg,0,sizeof(deg)); for(i=1;i<=n;i++) for(j=1;j<=n;j++) dp[i][j]=INF; for(i=1;i<n;i++){ scanf("%d%d",&j,&k); deg[j]++; deg[k]++; add(j,k); add(k,j); } dfs(1,-1); int ans=INF; for(i=1;i<=n;i++) ans=min(ans,dp[i][m]); printf("%d\n",ans); } return 0; }
原文:http://blog.csdn.net/xianxingwuguan1/article/details/18923795