樹形dp+01揹包例題

題目:
1,HDU 1011
2,HDU 1561(代碼中有核心部分的解析)
//HDU 1011
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int num=210;
struct node
{
    int v,next;
}e[num];
struct point
{
    int p,w;
}a[num];
int head[num],cnt;
int dp[num][num];//
bool vis[num];
int n,m,mx;
void int_i(void)
{
    memset(dp,0,sizeof(dp));
    memset(vis,0,sizeof(vis));
    memset(head,0,sizeof(head));
    cnt=0;
    mx=0;
    return ;
}
void addedge(int u,int v)
{
    e[++cnt].v=v;
    e[cnt].next=head[u];
    head[u]=cnt;
    return ;
}
void dfs(int u)
{
    for(int i=a[u].p;i<=m;i++)
    {
        dp[u][i]=a[u].w;
    }
    for(int i=head[u];i;i=e[i].next)
    {
        int v=e[i].v;
        if(vis[v]) continue;
        vis[v]=1;
        dfs(v);
        for(int j=m;j>a[u].p;j--)
        {
            for(int k=1;k<=j-a[u].p;k++)
            {
                dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]);
            }
        }
    }
    return;
}
int main()
{
    int u,v;
    while(scanf("%d%d",&n,&m)&&n!=-1&&m!=-1)
    {
        int_i();
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&a[i].p,&a[i].w);
            a[i].p=(a[i].p+19)/20;
        }
        for(int i=1;i<=n-1;i++)
        {
            scanf("%d%d",&u,&v);
            addedge(u,v);
            addedge(v,u);
        }

        if(m==0) {
            printf("0\n");
            continue;
        }
        vis[1]=1;
        dfs(1);
        vis[1]=0;
        printf("%d\n",dp[1][m]);
    }
    return 0;
}

//HDU 1561
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int num=210;
struct node
{
    int v,next;
}e[num];
int head[num],cnt;
int dp[num][num],w[num];
int n,m;
void int_i(void)
{
    cnt=0;
    memset(head,-1,sizeof(head));
    memset(dp,0,sizeof(dp));
    return ;
}
void addedge(int u,int v)
{
    e[++cnt].v=v;
    e[cnt].next=head[u];
    head[u]=cnt;
    return ;
}
void dfs(int u)
{

    for(int i=head[u];i!=-1;i=e[i].next)
    {
        int v=e[i].v;
        dfs(v);
        for(int j=m;j>1;j--)
        {
            for(int k=1;k<j;k++)//j-k>0.上面從大到小,下面從
            {
                dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]);
            }
        }
        //爲什麼j從m開始,而不是從2開始,這和01揹包的滾動數組是有關係的
        //注意:這裏dp雖然是二維的,但是僅僅有第二維:j,充當01揹包的滾動數組
        //第一維不屬於01揹包的內容,所以結合01揹包的滾動數組可以理解爲什麼兩層for循環是這樣寫的了;
    }
    return ;
}
int main()
{
    while(scanf("%d%d",&n,&m)&&(n||m))
    {
   		m++;//增加了一個0結點!!!
        int_i();
        int u;
        w[0]=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&u,&w[i]);
            addedge(u,i);
            dp[i][1]=w[i];
        }
        dfs(0);
        printf("%d\n",dp[0][m]);
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章