首页 > 代码库 > poj1947 Rebuilding Roads

poj1947 Rebuilding Roads

题解:

树形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;}

 

poj1947 Rebuilding Roads