bzoj 4254 树形dp

来源:互联网 发布:烟台华商网络怎么样 编辑:程序博客网 时间:2024/04/30 01:42

题意:给n个点,第i个点坐标(xi,yi),保证xi<xi1 且相邻两个点的y坐标不同。对于两个y坐标相等的点,如果两个点中间所有点的y坐标小于两个点的y坐标,那么两个点可以连一条边。给出m,k。求连m条边,使每个点上方的边数小于k的最大边长和,无解输-1。

每个点最多向右连出一条边。两条边的位置关系只可能是包含或没有交集。
那么这就是很多棵树。

建出树,树形dp,设f[i][j][k] 表示到点i,点i的子树中有j条选择的边,最大深度为k的最大边长和。
将k一维求一个前缀最大值,转移:f[i][j][k]=f[u][x][k]+f[i][jx][k]
最后用f[i][j][k]+len[i] 更新 f[i][j+1][k+1] 考虑是否选当前点。

如果i,j都枚举到size那么复杂度可以降为O(kn2)

#include <bits/stdc++.h>using namespace std;#define N 210int n,m,K,top,Case;int X[N],Y[N],st[N],pos[N],fa[N],len[N],size[N];int f[N][N][11],t[N];vector<int>vec[N];void dfs(int x){    for(int i=0;i<=K;i++)f[x][0][i]=0;    size[x]=1;    for(int i=0,u;i<vec[x].size();i++)    {        dfs(u=vec[x][i]);        size[x]+=size[u];        for(int j=min(m,size[x]);j>=0;j--)            for(int k=0;k<=K;k++)                for(int t=0;t<=size[u]&&t<=j;t++)                {                       if(f[x][j-t][k]!=-1&&f[u][t][k]!=-1)                        f[x][j][k]=max(f[x][j][k],f[u][t][k]+f[x][j-t][k]);                }    }    for(int i=min(m,size[x])-1;i>=0;i--)        for(int j=0;j<K;j++)            if(f[x][i][j]!=-1)                f[x][i+1][j+1]=max(f[x][i+1][j+1],f[x][i][j]+len[x]);    for(int i=1;i<=K;i++)        for(int j=0;j<=m&&j<=size[x];j++)            f[x][j][i]=max(f[x][j][i],f[x][j][i-1]);}int main(){    //freopen("tt.in","r",stdin);    while(scanf("%d%d%d",&n,&m,&K)!=EOF)    {        K--;        memset(f,-1,sizeof(f));        memset(t,-1,sizeof(t));        memset(size,0,sizeof(size));        for(int i=1;i<=n;i++)            scanf("%d%d",&X[i],&Y[i]);        top=0;        for(int i=1;i<=n;i++)        {            pos[i]=fa[i]=0;            vec[i].clear();        }        for(int i=1;i<=n;i++)        {            while(Y[i]>Y[st[top]]&&top)top--;            if(Y[i]==Y[st[top]]&&top)            {                   pos[st[top]]=i;                len[st[top]]=X[i]-X[st[top]];                top--;            }            st[++top]=i;        }        for(int i=1;i<=n;i++)            if(pos[i])            {                int p=0;                for(int j=1;j<i;j++)                    if(pos[j]&&X[pos[j]]>X[pos[i]])p=j;                if(p)vec[p].push_back(i);                fa[i]=p;            }        t[0]=0;        for(int i=1;i<=n;i++)            if(!fa[i]&&pos[i])            {                   dfs(i);                for(int j=m;j>=0;j--)                    for(int k=0;k<=size[i]&&k<=j;k++)                        if(t[j-k]!=-1&&f[i][k][K]!=-1)                            t[j]=max(t[j],t[j-k]+f[i][k][K]);            }        printf("Case %d: %d\n",++Case,t[m]);    }    return 0;}
0 0
原创粉丝点击