码迷,mamicode.com
首页 > 其他好文 > 详细

深探树形dp

时间:2018-12-07 14:58:32      阅读:229      评论:0      收藏:0      [点我收藏+]

标签:+=   img   ring   ++   end   cstring   play   src   nbsp   

  看到同学在写一道树形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\n",f[c[0]][m]);
    cout<<cnt<<endl;
    return 0;
}

 

深探树形dp

标签:+=   img   ring   ++   end   cstring   play   src   nbsp   

原文地址:https://www.cnblogs.com/chdy/p/10082247.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!