zoukankan      html  css  js  c++  java
  • codevs 2241 排序二叉树

    /*
    WTF
     写了好久了 开始的时候题目读错了 建图建错了
     搜索写的也不好 感觉会T 
     总之 第一次写的很low
     贴一下吧 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define N 40
    #define M 40
    using namespace std;
    int n,g[N*N][N*N],a[5][M*M];
    int num[5],ans,maxx,f[N*N][N*N];
    struct node
    {
        int c[4],data;
        int x[4],y[4];
    }p[N*N][N*N];
    int Get_place(int x,int y)
    {
        if(x<=n)return 1;
        if(y>(x-n)*2-1&&y<=2*n)return 4;
        if(y<=(x-n)*2-1)return 3;
        return 2;
    }
    int Dfs(int x,int y)
    {
        int sum=1;
        for(int i=1;i<=3;i++)
          for(int j=1;j<=3;j++)
            {
              if(p[x][y].c[i]<p[x][y].data&&p[x][y].c[j]>p[x][y].data
              &&f[p[x][y].x[i]][p[x][y].y[i]]==0&&f[p[x][y].x[j]][p[x][y].y[j]]==0)
                {
                  f[p[x][y].x[i]][p[x][y].y[i]]=1;f[p[x][y].x[j]][p[x][y].y[j]]=1;
                  sum=max(sum,Dfs(p[x][y].x[i],p[x][y].y[i])+Dfs(p[x][y].x[j],p[x][y].y[j]));
                  f[p[x][y].x[i]][p[x][y].y[i]]=0;f[p[x][y].x[j]][p[x][y].y[j]]=0;
                }
            }
        for(int i=1;i<=3;i++)
          {
              if(f[p[x][y].x[i]][p[x][y].y[i]]==0)
                {
                  f[p[x][y].x[i]][p[x][y].y[i]]=1;
                  sum=max(sum,Dfs(p[x][y].x[i],p[x][y].y[i]));
                  f[p[x][y].x[i]][p[x][y].y[i]]=0;
                }
          }
        return sum;
    }
    int main()
    {
        scanf("%d",&n);
        for(int k=1;k<=4;k++)
          for(int i=1;i<=n*n;i++)
            scanf("%d",&a[k][i]);
        num[4]=n*n;
        for(int i=1;i<=n*2;i++)
          for(int j=1;j<=2*i-1;j++)
            {
              int pi=Get_place(i,j);
              if(pi==4)g[i][j]=a[pi][num[pi]--];
              else g[i][j]=a[pi][++num[pi]];
            }
        for(int i=1;i<=n*2;i++)
          for(int j=1;j<=i*2-1;j++)
            {
              if(j&1)
                {
                  p[i][j].c[1]=g[i][j-1];
                  p[i][j].c[2]=g[i][j+1];
                  p[i][j].c[3]=g[i+1][j+1];
                  p[i][j].data=g[i][j];
                  p[i][j].x[1]=i;p[i][j].y[1]=j-1;
                  p[i][j].x[2]=i;p[i][j].y[2]=j+1;
                  p[i][j].x[3]=i+1;p[i][j].y[3]=j+1;
                }
              else 
                {
                  p[i][j].c[1]=g[i][j-1];
                  p[i][j].c[2]=g[i][j+1];
                  p[i][j].c[3]=g[i-1][j-1];
                  p[i][j].data=g[i][j];
                  p[i][j].x[1]=i;p[i][j].y[1]=j-1;
                  p[i][j].x[2]=i;p[i][j].y[2]=j+1;
                  p[i][j].x[3]=i-1;p[i][j].y[3]=j-1;
                }
              if(j==1)
                {
                  p[i][j].c[1]=g[2*n+1-i][j];
                  p[i][j].x[1]=2*n+1-i;
                  p[i][j].y[1]=4*n-2*i+1;
                }
              if(j==i*2-1)
                {
                  p[i][j].c[2]=g[2*n+1-i][4*n-2*i+1];
                  p[i][j].x[2]=2*n+1-i;
                  p[i][j].y[2]=4*n-2*i+1;
                }
              if(i==2*n&&(j&1))
                {
                  p[i][j].c[3]=g[i][2*n-j];
                  p[i][j].x[3]=i;
                  p[i][j].y[2]=2*n-j;
                }
            }
        //int xi,yi;
        //while(~scanf("%d%d",&xi,&yi))
        //printf("%d
    %d %d %d
    ",p[xi][yi].data,p[xi][yi].c[1],p[xi][yi].c[2],p[xi][yi].c[3]);
        for(int i=1;i<=n*2;i++)
          for(int j=1;j<=i*2-1;j++)
            {
              memset(f,0,sizeof(f));
              f[i][j]=1;ans=max(Dfs(i,j),ans);
            }
        printf("%d
    ",ans);
        return 0;
    }
    /*
     换一种建图方式 这样很机智啊 然而我并没有想到
     保留原来的三个4个三角形 然后建图 而不是搞到一个大的三角形里再建图
     具体看代码吧
     我们得到了每个点相邻的三个点的权值以后 需要枚举根 然后扩展结点 统计最大值
     对于每一个点 我们并不需要分开考虑左右都选还是直选左或者直选右
     我们左右都扩展一遍然后取大并做和就ok
     但是介于二叉搜索树的要求 如果我们扩展节点时只要求他和相邻父亲比较大小的话
     不能满足左子树的每个节点都小于根 所以我们扩展的时候再维护一下边界 这样的话就使得树满足性质了 
     然而时间复杂度会很大 需要记忆化 
     再然而我们这个状态不好表示 只能用3维 f[i][j][k] 表示从j到i 边界是k(不管是左还是右)以i为根的最优解 
     再再然而我们又发现这个状态爆空间了-- 降维的话 如果把第三维降掉显然会有重复
     其实我们的j到i是很浪费的 我们可以压缩第二维 把到从j改为从i的第几个相邻的点到的
     这样我们就能存下了 然后就是细节问题了 
     开始存小三角形用的5*20*20 n<=18 RE到死....忘记存的三角形不是矩形了.....WTF 
    */
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define N 40//数组开大保平安 
    #define M 20*20*4
    using namespace std;
    int n,g[5][N][N],s[M][4],ans;
    bool vis[M][M];
    int f[M][5][M];
    void Init()
    {
        cin>>n;
        for(int k=1;k<=4;k++)
          for(int i=1;i<=n;i++)
            for(int j=1;j<=i*2-1;j++)
              cin>>g[k][i][j];
    }
    void Add(int x,int y)
    {
        if(vis[x][y]==0)
          {
              vis[x][y]=1;
              s[x][++s[x][0]]=y;
          }
        if(vis[y][x]==0)
          {
              vis[y][x]=1;
              s[y][++s[y][0]]=x;
          }
    }
    void Build_tree()
    {
        for(int k=1;k<=4;k++)//内部点 
          for(int i=2;i<=n-1;i++)
            for(int j=2;j<2*i-1;j++)
              if(j&1)
                {
                    Add(g[k][i][j],g[k][i][j+1]);
                    Add(g[k][i][j],g[k][i][j-1]);
                    Add(g[k][i][j],g[k][i+1][j+1]);
                }
              else 
                {
                  Add(g[k][i][j],g[k][i][j+1]);
                    Add(g[k][i][j],g[k][i][j-1]);
                    Add(g[k][i][j],g[k][i-1][j-1]);
                }
        for(int k=1;k<=4;k++)//底边界偶数点
          for(int i=2;i<=n*2-1;i+=2)
            {
              Add(g[k][n][i],g[k][n][i+1]);
              Add(g[k][n][i],g[k][n][i-1]);
              Add(g[k][n][i],g[k][n-1][i-1]);
            }
        for(int i=1;i<=n;i++)//侧边界点
          {
              Add(g[1][i][2*i-1],g[2][i][1]);
              Add(g[2][i][2*i-1],g[3][i][1]);
              Add(g[3][i][2*i-1],g[1][i][1]);
          }    
        for(int i=1;i<=n*2-1;i+=2)//底边界奇数点 
          {
              Add(g[1][n][i],g[4][n-(i/2)][1]);
            Add(g[2][n][i],g[4][i/2+1][(i/2+1)*2-1]);
            Add(g[3][n][i],g[4][n][2*n-i]);
          } 
    }
    int DP(int i,int l1,int l2)//因为要用到i来自哪 所以左右边界可能颠倒 
    {
        int from=1;
        while(s[i][from]!=l2)from++;//i是从i的第几个相邻的点连过来的 
        if(f[i][from][l1]>0)return f[i][from][l1];//记忆化 
        int l,r,lmax=0,rmax=0;
        if(l1>l2)l=l2+1,r=l1;//修正左右边界 
        else l=l1,r=l2-1;
        for(int j=1;j<=3;j++)
          if(j!=from&&l<=s[i][j]&&r>=s[i][j])
            {
              if(s[i][j]<i)lmax=max(lmax,DP(s[i][j],l,i));
              else rmax=max(rmax,DP(s[i][j],r,i));
            }
        f[i][from][l1]=lmax+rmax+1;
        return f[i][from][l1];
    }
    void Dfs()
    {
        for(int i=1;i<=n*n*4;i++)//枚举根节点 
          {
              int lmax=0,rmax=0;
            for(int j=1;j<=3;j++)
              if(s[i][j]<i)lmax=max(lmax,DP(s[i][j],1,i));//左子树的所有数在1-i-1之间 
              else rmax=max(rmax,DP(s[i][j],n*n*4,i));//右子树的所有数在i+1-n*n*4之间 
            ans=max(ans,1+lmax+rmax);
          }
    }
    int main()
    {
        //freopen("bstree.in","r",stdin);
        //freopen("bstree.out","w",stdout);
        Init();
        Build_tree();
        Dfs();
        cout<<ans<<endl;
        return 0;
    }
  • 相关阅读:
    深入了解接口
    深入.NET平台C#编程 测试题分析
    如何设计高级的数据库
    数据库查询的基础技巧
    回顾Spring MVC_01_概述_入门案例
    初学My Batis之入门
    Spring MVC之视图解析器和URL-Pattern的配置方案
    SpringMVC之入门
    WebService入门
    Spring之实现任务调度
  • 原文地址:https://www.cnblogs.com/yanlifneg/p/5578663.html
Copyright © 2011-2022 走看看