poj 1947 树型DP(依赖背包)

前端之家收集整理的这篇文章主要介绍了poj 1947 树型DP(依赖背包)前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

题目:http://poj.org/problem?id=1947

题意:给一颗树包含N个节点,问你最少剪去几个边可以得到一颗包含P个节点的子树。

解题思路:这个题目让我想了一天加一晚上,开始一直想用DP[i][j]表示以i为父节点的树,保留j个子节点至少要剪的边数,结果一直想不出思路,实在没办法,在网上找的解题报告很多也是这个想法,但是在我的不解努力中,终于找到一个独树一帜的解题思路:用DP[i][j]表示,以i为父节点的树,删去j个点,至少要剪去几条边。这样就和原来的思路 相反了,然后解题就一下子简单了好多,直接就是一个很简单很简单的树型dp了,也就是一个很裸的依赖背包了。然后自己写了一个,感觉比参考的代码还要高效!!

解题感想:遇到问题时,如果用一种常规的思路一直解决不了,那么也许用一个相反的思路就可以把问题变的很简单,很简单了。

代码如下:

//1947	Accepted	392K	0MS	C++	1271B	2012-07-24 08:04:30
#include <stdio.h>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;
#define N 200
#define M (1<<30)
vector <int> tree[N];
int num,remain,root,ans;
int dp[N][N];//dp[i][j]表示以i为根,删除j个还在最少需要删几个边
int dfs(int key)
{
    int length=tree[key].size(),size=1;
    int i,j,k,v,p;
    for(i=0;i<length;i++)
    {
        v=tree[key][i];
        p=dfs(v);   size+=p;
        for(j=num-remain;j>0;j--)
            for(k=1;k<=min(j,p);k++)
                dp[key][j]=min(dp[key][j],dp[key][j-k]+dp[v][k]);
    }
    dp[key][size]=1;
    if(key!=root&&size>=remain)
        ans=min(ans,dp[key][size-remain]+1);
    tree[key].clear();
    return size;
}
void init()
{
    int i,x,y;    bool de[N];
    ans=M;
    memset(de,true,sizeof(de));
    for(i=1;i<num;i++)
    {
        scanf("%d%d",&x,&y);
        tree[x].push_back(y);
        de[y]=false;
    }
    for(i=1;i<num;i++)
        if(de[i])
        {
            root=i;break;
        }
    for(i=1;i<=num;i++)
    {
        dp[i][0]=0;
        for(int j=1;j<=num;j++)
        dp[i][j]=M;
    }
}
int main()
{
    while(cin>>num>>remain)
    {
        init();
        ans=min(ans,dp[root][dfs(root)-remain]);
        cout<<ans<<endl;
    }
}
nyoj代码
 
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
const int N = 510;
const int MAX = (1 << 30);
using namespace std;

struct Edg{
    int nod,next;
}edg[2 * N];
int nod[N],k;
bool vis[N];
int dp[N][N];
int ans,n,remain;

void add_edg(int x,int y){
    edg[k].nod = y;
    edg[k].next = nod[x];
    nod[x] = k ++;
}

void init(){
    int x,y;
    k = 0;  ans = MAX;
    memset(vis,sizeof(vis));
    memset(nod,-1,sizeof(nod));
    cin >> n >> remain;
    for(int i = 0; i < n - 1; i ++){
        cin >> x >> y;
        add_edg(x,y);
        add_edg(y,x);
    }
    for(int i = 1;i <= n ;i ++){
        dp[i][0] = 0;
        for(int j = 1; j <= n; j ++)
            dp[i][j] = MAX;
    }
}

int dfs(int key){
    vis[key] = false;
    int v,p,size = 1;
    for(int i = nod[key]; i != -1; i = edg[i].next){
        v = edg[i].nod;
        if(!vis[v]) continue;
        p = dfs(v); size += p;
        for(int j = n - remain; j > 0; j --){
            for(int k = 1; k <= min(p,j);k ++){
                dp[key][j] = min(dp[key][j],dp[key][j - k] + dp[v][k]);
            }
        }
    }
    if(key == 1) dp[key][size] = 0;
    else dp[key][size] = 1;
    if(key != 1 && size >= remain)
        ans = min(ans,dp[key][size - remain] + 1);
    return size;
}

int main(){
    //freopen("1.txt","r",stdin);
    //freopen("2.txt","w",stdout);
    int T,cas = 1;
    cin >> T;
    while(T --){
        init();
        ans = min(ans,dp[1][dfs(1) - remain]);
        printf("case #%d: %d\n",cas ++,ans);
    }
}        
原文链接:https://www.f2er.com/javaschema/286707.html

猜你在找的设计模式相关文章