深探树形dp

Posted chdy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深探树形dp相关的知识,希望对你有一定的参考价值。

  看到同学在写一道树形dp,好奇直接拿来写,发现很不简单。

技术分享图片

如图,看上去是不是很像选课,没错这不是选课,升级版吧,多加了点东西罢了。简单却调了一晚上和一上午。

思路:很简单强联通分量+缩点+树形dp。直接莽啊,发现强联通分量不是很会求,码力不好一直调。然后开始缩点,这个缩点就分成的讲究了你咋么缩都行反正是一张无向图不过要注意最后图是一个连通图,每个节点都会直接和间接和0(人造源点相连。

然后树上dp即可。很简单。树上dp出锅了,一直调,然后改成二叉树dp,还是wa。

发现缩点GG了根本不能那样缩,然后考虑缩点的细节。然后实现码力好点就行了。简单。

#include<iostream>
#include<cstring>
#include<string>
#include<ctime>
#include<cmath>
#include<iomanip>
#include<algorithm>
#include<queue>
#include<vector>
#include<stack>
#include<cstdio>
#include<map>
#include<deque>
#include<set>
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}
    return x*f;
}
const int maxn=102;
int n,m;
int lin[maxn],ver[maxn],nex[maxn],len=0;
int v[maxn],w[maxn],dfn[maxn],low[maxn],c[maxn];
int st[1000],top=0,vis[maxn],num=0,cnt=0,ru[maxn];
int cv[maxn],cw[maxn],f[maxn][600],ls[maxn],rx[maxn];//左儿子,右兄弟
vector<int>q[maxn];
void add(int x,int y)
{
    ver[++len]=y;
    nex[len]=lin[x];
    lin[x]=len;
}
void tarjan(int x)
{
    dfn[x]=low[x]=++num;
    st[++top]=x;vis[x]=1;
    for(int i=lin[x];i;i=nex[i])
    {
        int tn=ver[i];
        if(dfn[tn]==0)
        {
            tarjan(tn);
            low[x]=min(low[x],low[tn]);
        }
        else if(vis[tn]==1)low[x]=min(low[x],dfn[tn]);
    }
    if(dfn[x]==low[x])
    {
        cnt++;int y;
        do
        {
            y=st[top--];vis[y]=0;
            c[y]=cnt;q[cnt].push_back(y);
        }
        while(x!=y);
    }
}
void dfs(int i,int j)
{
    if(i==-1||j==0||f[i][j]>0)return;
    dfs(rx[i],j);
    f[i][j]=max(f[i][j],f[rx[i]>0?rx[i]:0][j]);
    int vx=j-cw[i];
    for(int k=0;k<=vx;k++)
    {
        dfs(ls[i],vx-k);
        dfs(rx[i],k);
        f[i][j]=max(f[i][j],f[ls[i]>0?ls[i]:0][vx-k]+f[rx[i]>0?rx[i]:0][k]+cv[i]);
    }
}
int main()
{
    //freopen("1.in","r",stdin);
    n=read();m=read();cout<<n<<endl;
    for(int i=1;i<=n;i++)w[i]=read();
    for(int i=1;i<=n;i++)v[i]=read();
    for(int i=1;i<=n;i++){int x;x=read();add(x,i);}
    for(int i=1;i<=n;i++)if(dfn[i]==0)tarjan(i);
    /*for(int x=0;x<=n;x++)
    {
        for(int i=lin[x];i;i=nex[i])
        {
            int tn=ver[i];
            if(vis[x]==0)cv[c[x]]+=v[x],cw[c[x]]+=w[x];
            if(vis[tn]==0)cv[c[tn]]+=v[tn],cw[c[tn]]+=w[tn];
            vis[x]=1;vis[tn]=1;
            if(c[x]==c[tn]){if(ins[c[x]]==0)cadd(c[0],c[x]),ins[c[x]]=1;}
            cadd(c[x],c[tn]);
        }
    }*///预处理完成!开始树形dp, 书上dp出现失误不知道哪错了,多叉转二叉!
    memset(rx,-1,sizeof(rx));memset(ls,-1,sizeof(ls));
    for(int x=1;x<=n;x++){cw[c[x]]+=w[x];cv[c[x]]+=v[x];}
    for(int x=1;x<=cnt;x++)
    {
        for(int j=0;j<q[x].size();j++)
        {
            int te=q[x][j];
            for(int i=lin[te];i;i=nex[i])
            {
                int tn=ver[i];
                if(f[x][c[tn]]==0&&x!=c[tn])
                {
                    f[x][c[tn]]=1;
                    rx[c[tn]]=ls[x];
                    ls[x]=c[tn];
                    ru[c[tn]]++;
                }
            }
        }
    }
    for(int i=1;i<=cnt;i++)if(ru[i]==0)rx[i]=ls[0],ls[0]=i;
    memset(f,0,sizeof(f));
    //dfs(c[0],m);
    //printf("%d
",f[c[0]][m]);
    cout<<cnt<<endl;
    return 0;
}

 

以上是关于深探树形dp的主要内容,如果未能解决你的问题,请参考以下文章

动态规划_计数类dp_数位统计dp_状态压缩dp_树形dp_记忆化搜索

Starship Troopers(HDU 1011 树形DP)

HDU1520 Anniversary party(树形dp入门题)

[填坑][支线任务]树形DP 树形背包

hdu1561 树形dp+背包

BZOJ_1060_时态同步_树形DP