速度与激情7真是好电影。
题意
给一棵树,问至少删除多少边,可以独立出一棵有p个点的子树。
输入输出
Input
Line 1: Two integers, N and P
Lines 2..N: N-1 lines, each with two integers I and J. Node I is node J’s parent in the tree of roads.
Output
A single line containing the integer that is the minimum number of roads that need to be destroyed for a subtree of P nodes to be isolated.
分析
dp[i][j]表示编号为i的点为根的子树,删除某些边后剩j个点,最少需要删除的边的个数。
状态转移是这样的,对每个根节点,遍历他的所有儿子,遍历所有可取的j值,对当前儿子的子树的所有可能j值,跑dp[now][j]=min(dp[now][j]+1, dp[now][j-k]+dp[son][k]);
不过这个状态转移方程是不完整的,因为实现时会遇到一些麻烦。比如我从小到大遍历j值,导致先改变的j值影响了后面改变j值,因此需要加一维度,事实上只需要反过来遍历j就可。还有由于k可以取不同的值,上面的dp[now][j]也需要和现在已有的dp[now][j]进行比较。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define mxn 200
#define inf 0x3f3f3f3f
int n,p;
int first[mxn],nxt[mxn],vv[mxn],cnt;
int node[mxn],e[mxn];
int dp[mxn][2][mxn];
int father[mxn];
int root;
void init(){
memset(father,-1,sizeof(father));
memset(dp,0x3f,sizeof(dp));
memset(first,-1,sizeof(first));
cnt=0;
}
void add(int u,int v){
nxt[cnt]=first[u];
first[u]=cnt;
vv[cnt]=v;
++cnt;
}
void dfs(int now){
node[now]=1;
e[now]=0;
for(int i=first[now];i!=-1;i=nxt[i]){
dfs(vv[i]);
++e[now];
node[now]+=node[vv[i]];
}
int temcnt=1;
dp[now][0][1]=0;
//for(int i=1;i<=node[now];++i)
for(int j=first[now];j!=-1;j=nxt[j]){
memset(dp[now][temcnt%2],0x3f,sizeof(dp[now][temcnt%2]));
dp[now][temcnt%2][1]=dp[now][(temcnt+1)%2][1]+1;
for(int i=1;i<=node[now];++i)
for(int k=1;k<i&&k<=node[vv[j]];++k){
int tem=min(dp[now][(temcnt+1)%2][i]+1,dp[now][(temcnt+1)%2][i-k]+dp[vv[j]][(e[vv[j]])%2][k]);
dp[now][temcnt%2][i]=min(dp[now][temcnt%2][i],tem);
}
++temcnt;
}
}
void setroot(){
root=1;
while(father[root]!=-1) root=father[root];
}
int main(){
freopen("data.txt","r",stdin);
freopen("myans.txt","w",stdout);
while(scanf("%d%d",&n,&p)!=EOF){
if(n==1){
puts("0");
continue;
}
init();
for(int i=1;i<n;++i){
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
father[v]=u;
}
setroot();
dfs(root);
int ans=dp[root][e[root]%2][p];
for(int i=1;i<=n;++i) if(i!=root)
ans=min(ans,dp[i][e[i]%2][p]+1);
printf("%d\n",ans);
}
return 0;
}