POJ1947【树形DP】

来源:互联网 发布:数据信息安全管理制度 编辑:程序博客网 时间:2024/06/08 05:28

题意:

求 the minimum number of roads that need to be destroyed for a subtree of P nodes to be isolated.

思路:

  • dp[i][j]:以当前节点i为根保留j个节点的个数,注:必须保留 i 节点。
  • 构造对当前根节点和子节点之间的关系。
    1. 去掉以节点son的子树,那就是一刀切了子树,然后剩下当前这么多节点。
      dp[father][node_num] = dp[father][node_num] + 1.
    2. 不去掉以节点son的子树,那么就是枚举以节点son子树中剩下节点个数,
      dp[father][j] = dp[son][k] + dp[father][j-k];
  • 最后还要考虑所有节点都有可能做这棵有P节点树的根,
    分两种,
    1. 对于一开始假定搜的根,前驱没有边,所以ans = dp[node][P]
    2. 对于那些除了这个(一开始假定搜的根),前驱都有边,所以要切掉才能使得以当前节点为根,ans=dp[node][P]+1.

Code:

//#include <bits/stdc++.h>#include<cstdio>#include<string.h>#include<algorithm>using namespace std;typedef pair<int,int> PII;typedef long long LL;//#pragma comment(linker, "/STACK:102400000,102400000")const int INF=0x3f3f3f3f;const int N=2e2+10;struct Edge{    int v;    int next;}edge[N<<1];int head[N],tol;int n,P;void init(){    tol=0;    memset(head,-1,sizeof(head));}void add(int u,int v){    edge[tol].v=v;    edge[tol].next=head[u];    head[u]=tol++;}int dp[N][N];bool vis[N];void DFS(int u){    int v,sum=0;    dp[u][1]=0;     //初始化只剩根节点为0(假设没有子树存在)    for(int i=head[u];~i;i=edge[i].next){        v=edge[i].v;        if(vis[v]) continue;        vis[v]=true;        sum++;        DFS(v);        for(int j=P;j>=1;j--){            dp[u][j]=dp[u][j]+1; //砍掉这棵子树            for(int k=1;k<j;k++)    //枚举子树中剩下的节点数,因为保证每棵树根节点存在,所以k<j                dp[u][j]=min(dp[u][j],dp[v][k]+dp[u][j-k]);        }    }}int main(){    int u,v;    while(~scanf("%d%d",&n,&P)){        init();        for(int i=1;i<n;i++){            scanf("%d%d",&u,&v);            add(u,v);            add(v,u);        }        int ans=INF,root=1;        memset(vis,false,sizeof(vis));        memset(dp,INF,sizeof(dp));        vis[root]=true;        DFS(root);        ans=dp[root][P];        //一开始假设1为根的ans        for(int j=1;j<=n;j++)            if(root!=j)         //不是(那个假定根)的节点的ans                ans=min(ans,dp[j][P]+1);        printf("%d\n",ans);    }    return 0;}
原创粉丝点击