标签:
题解:
树形dp+背包
dp[i][j]表示以i为根,保留j个节点所需要删除的最少边数
默认1为根。在最后计算时,非1的树根要加1(砍去父亲节点)
注意初始化。。。。。
代码:
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; #define pb push_back #define mp make_pair #define se second #define fs first #define LL long long #define CLR(x) memset(x,0,sizeof x) #define MC(x,y) memcpy(x,y,sizeof(x)) #define SZ(x) ((int)(x).size()) #define FOR(it,c) for(__typeof((c).begin()) it=(c).begin();it!=(c).end();it++) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 //typedef pair<int,int> P; const double eps=1e-9; const int maxn=200; const int mod=1e9+7; const int INF=1e9; int N,P,cnt; int head[maxn],Size[maxn],num[maxn]; int dp[maxn][maxn]; struct Edge{ int v,nxt; }edge[maxn]; void Init(){ cnt=0; memset(head,-1,sizeof(head)); memset(Size,0,sizeof(Size)); memset(num,0,sizeof(num)); for(int i=0;i<=N;i++) for(int j=0;j<=N;j++) dp[i][j]=INF; } void addEdge(int u,int v){ edge[cnt].v=v; edge[cnt].nxt=head[u]; head[u]=cnt++; num[u]++; } void dfs(int u){ Size[u]=1; for(int i=head[u];i!=-1;i=edge[i].nxt){ int v=edge[i].v; dfs(v); Size[u]+=Size[v]; } dp[u][Size[u]]=0; } void DP(int u){ for(int i=head[u];i!=-1;i=edge[i].nxt){ int v=edge[i].v; DP(v); for(int j=Size[u];j>0;j--) for(int s=1;s<=min(j,Size[v]);s++) dp[u][j]=min(dp[u][j],dp[u][j-s]+dp[v][s]-1); } } int main(){ scanf("%d%d",&N,&P); Init(); for(int i=1;i<=N-1;i++){ int x,y; scanf("%d%d",&x,&y); addEdge(x,y); } for(int i=1;i<=N;i++) dp[i][1]=num[i]; dfs(1); DP(1); int ans=dp[1][P]; for(int i=2;i<=N;i++) ans=min(ans,dp[i][P]+1); printf("%d\n",ans); return 0; }
标签:
原文地址:http://www.cnblogs.com/byene/p/5854442.html