• 测试总结


    今后将有大量试题与博客出没(想回去中考。。。)

    T1:

    FBI树

    我们可以把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全“1”串称为I串,既含“0”又含“1”的串则称为F串。

    FBI树是一种二叉树,它的结点类型也包括F结点,B结点和I结点三种。由一个长度为2^N的“01”串S可以构造出一棵FBI树T,递归的构造方法如下:

    1) T的根结点为R,其类型与串S的类型相同;

    2) 若串S的长度大于1,将串S从中间分开,分为等长的左右子串S1S2;由左子串S1构造R的左子树T1,由右子串S2构造R的右子树T2

    现在给定一个长度为2^N的“01”串,请用上述构造方法构造出一棵FBI树,并输出它的后序遍历序列。

    看上去很麻烦,实际上就是根据原字符串进行处理,每次将字符串从中间分为两等长字符串,再分别判断类型

    结合代码讲下:

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<queue>
      4 #include<algorithm>
      5 #include<cstring>
      6 #include<string>
      7 using namespace std;
      8 int n;
      9 struct node{     //其中数组大小很鬼畜,一开始大小为1024左右,然而RE,就开了十倍大小,luogu过了
     10     int size;
     11     char a[10300];
     12     char type;
     13 }nd[10240];
     14 int po(int k){      //快速幂,其实用pow好像慢不了多少,因为本函数在本题中并不常用
     15     int t=2;
     16     int p=1;
     17     while(k){
     18         if(k&1)
     19             p*=t;
     20         t*=t;
     21         k>>=1;
     22     }
     23     return p;
     24 }
     25 inline void search(int numb,int de){      //因为用的特别多,加了inline,递归处理字符串
     26     int l=numb*2;         //根据满二叉树的节点编号特征将节点编号表示出来
     27     int r=numb*2+1;
     28     nd[l].size=nd[numb].size/2;
     29     nd[r].size=nd[numb].size/2;
     30     for(int i=0;i<nd[numb*2].size;i++){
     31         nd[l].a[i]=nd[numb].a[i];
     32         nd[r].a[i]=nd[numb].a[i+nd[l].size];
     33     }  //一人一半
     34     bool ok1=0,ok0=0;
     35     for(int i=0;i<nd[l].size;i++){  //遍历判断字符串类型
     36         if(nd[l].a[i]=='1')
     37             ok1=1;
     38         if(nd[l].a[i]=='0')
     39             ok0=1;
     40         if(ok1&&ok0)
     41             nd[l].type='F';
     42         else if(!ok1)
     43             nd[l].type='B';
     44         else if(!ok0)
     45             nd[l].type='I';
     46     }
     47     ok1=0;ok0=0;
     48     for(int i=0;i<nd[r].size;i++){
     49         if(nd[r].a[i]=='1')
     50             ok1=1;
     51         if(nd[r].a[i]=='0')
     52             ok0=1;
     53         if(ok1&&ok0)
     54             nd[r].type='F';
     55         else if(!ok1)
     56             nd[r].type='B';
     57         else if(!ok0)
     58             nd[r].type='I';
     59     }
     60     if(de==n+1) return;  //处理完毕的边界条件
     61     else{                //递归处理
     62         search(l,de+1);
     63         search(r,de+1);
     64     }
     65 }
     66 //<-编号鬼畜了 
    67
    void print(int numb){ //后序输出,也是递归 68 if(numb>po(n+1)-1) return; 69 print(numb*2); 70 print(numb*2+1); 71 putchar(nd[numb].type); 72 } 73 int main(){ 74 //freopen("fbi.in","r",stdin); 75 //freopen("fbi.out","w",stdout); 76 scanf("%d",&n); 77 scanf("%s",nd[1].a); 78 nd[1].size=po(n); 79 bool ok1,ok0; 80 for(int i=0;i<nd[1].size;i++){ //判断原字符串 81 if(nd[1].a[i]=='1') 82 ok1=1; 83 if(nd[1].a[i]=='0') 84 ok0=1; 85 if(ok1&&ok0) 86 nd[1].type='F'; 87 else if(!ok1) 88 nd[1].type='B'; 89 else if(!ok0) 90 nd[1].type='I'; 91 } 92 search(1,1);/* 93 for(int i=1;i<=15;i++){ 94 cout<<nd[i].size<<endl; 95 for(int j=0;j<nd[i].size;j++) 96 cout<<nd[i].a[j]; 97 cout<<endl; 98 cout<<nd[i].type<<endl; 99 cout<<endl; 100 } 调试用的*/ 101 print(1); 102 return 0; 103 }

    这回显示行号以示友好...

    本题很简单,然而本机测试无伤,手动测试无伤,lemon测试不过???丢了10分,导致掉了3名

    那个数据还是不属于数据范围的...

    T2:

    医院设置

    设有一棵二叉树,如图:

    其中,圈中的数字表示结点中居民的人口。圈边上数字表示结点编号,现在要求在某个结点上建立一个医院,使所有居民所走的路程之和为最小,同时约定,相邻接点之间的距离为1。如上图中,

    若医院建在1 处,则距离和=4+12+2*20+2*40=136;若医院建在3 处,则距离和=4*2+13+20+40=81……

    就是求路程最小情况的总路程

    乍一看:又是树?LCA?

    看看luogu标签(当然我是刚刚(考试后)看的):

    到底是啥?

    一琢磨就知道这好像是最短路问题,看看可爱的数据范围:

    第一行一个整数n,表示树的结点数。(n≤100)

    n3好像没问题

    就是用Floyd

    代码(5分钟的产品...):

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<algorithm>
    #include<string>
    #include<cstring>
    using namespace std;
    int n;
    int peo[105];
    int dis[105][105];
    int main(){
        //freopen("hospital.in","r",stdin);
        //freopen("hospital.out","w",stdout);
        memset(dis,0x3f,sizeof(dis));
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            dis[i][i]=0;
        for(int i=1;i<=n;i++){
            int a,b;
            scanf("%d%d%d",&peo[i],&a,&b);
            if(a!=0){
                dis[i][a]=1;
                dis[a][i]=1;
            }
            if(b!=0){
                dis[i][b]=1;
                dis[b][i]=1;
            }
        }
        for(int k=1;k<=n;k++)
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    if(dis[i][j]>dis[i][k]+dis[k][j]){
                        dis[i][j]=dis[i][k]+dis[k][j];
                        dis[j][i]=dis[i][k]+dis[k][j];
                    }
        int minn=2147483647;
        for(int i=1;i<=n;i++){
            int sum=0;
            for(int j=1;j<=n;j++){
                sum+=peo[j]*dis[i][j];
            }
            minn=min(minn,sum);
        }
        cout<<minn;
        return 0;
    }

    Floyd模板加枚举暴力,不解释...

    T3:

    加分二叉树

    设一个nn个节点的二叉树tree的中序遍历为(1,2,3,…,n1,2,3,,n),其中数字1,2,3,…,n1,2,3,,n为节点编号。每个节点都有一个分数(均为正整数),记第ii个节点的分数为di,treedi,tree及它的每个子树都有一个加分,任一棵子树subtreesubtree(也包含treetree本身)的加分计算方法如下:

    subtreesubtree的左子树的加分× subtreesubtree的右子树的加分+subtreesubtree的根的分数。

    若某个子树为空,规定其加分为11,叶子的加分就是叶节点本身的分数。不考虑它的空子树。

    试求一棵符合中序遍历为(1,2,3,…,n1,2,3,,n)且加分最高的二叉树treetree。要求输出;

    (1)treetree的最高加分

    (2)treetree的前序遍历

    这个题看似难,

    实际确实很难

    最常见的解法就是区间dp和记忆化搜索(都不会

    代码:

    #include<iostream>
    #include<cstdio>
    using namespace std;
    int n;
    long long dp[35][35];         //注意,和有可能大于231,用dp_i_j表示从i——j最大情况
    int rt[35][35];
    int a[35];
    void print(int l, int r) {     //同T1递归处理
        if(l>r)return;
        if(l==r){
            printf("%d ",l);
            return;
        }
        printf("%d ",rt[l][r]);
        print(l,rt[l][r]-1);
        print(rt[l][r]+1,r);
    }
    int main(){
        //freopen("binary.in","r",stdin);
        //freopen("binary.out","w",stdout);
      scanf("%d",&n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            dp[i][i]=a[i];
            dp[i][i-1]=1;                //处理这里的目的是接下来有可能k=i,此时无右子树,所以需将其处理为1
            rt[i][i]=i;
        }
        for(int len=2;len<=n;len++){     //枚举区间,即需处理范围
            for(int i=1;i<=n-len+1;i++){
                int j=i+len-1;
                for(int k=i;k<=j;k++){   //枚举根结点
                    if(!dp[k+1][j]) dp[k+1][j]=1;    //将空区间设为1
                    if(!dp[i][k])dp[i][k]=1;
                    if(dp[i][k-1]*dp[k+1][j]+a[k]>dp[i][j]){
                        dp[i][j]=dp[i][k-1]*dp[k+1][j]+a[k];   //状态转移,找到最优方案将其保存
                        rt[i][j]=k;                            //此处不用max()函数因为还要判断保存根结点
                    }
                }
            }
        }
        cout<<dp[1][n]<<endl;
        print(1,n);
        return 0;
    }

     由题意可知,要求的最大加分即为左右两子树乘积加根结点,所以dp方程如下:

      dp[i][j]=max(dp[i][k-1]*dp[k+1][j]+a[k])

    同时进行根的保存,用于输出前序遍历,此处rt[i][j]指的从i——j加分最大子树的根结点,方便递归处理,

    最后输出全局结果,就是把整个树的情况输出,dp[1][n]显然指从1——n结点成树最大情况,而print 1——n指的是将刚刚1——n结点成树的图输出

  • 相关阅读:
    一句话解释各种虚拟币的用途
    php 网站301重定向设置代码实战案例
    seo网页加速技术,预加载 DNS Prefetching 详解
    AI赌神称霸德扑的秘密,刚刚被《科学》“曝光”了
    java实现 HTTP/HTTPS请求绕过证书检测代码实现
    pyspider源码解读--调度器scheduler.py
    pyspider操作千万级库,pyspider在对接量级较大库的策略
    尼克《人工智能简史》谈人工智能的历史、现实与未来
    CentOS7使用yum命令安装Java1.8
    php ci nginx 伪静态rewrite配置方法
  • 原文地址:https://www.cnblogs.com/648-233/p/10998826.html
Copyright © 2020-2023  润新知