• 17.8.15第七次测试


    1.二叉树

    【问题描述】
    二叉排序树或者是一棵空树,或者是具有下列性质的二叉树:
    (1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
    (2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
    (3)左、右子树也分别为二叉排序树;
    (4)没有键值相等的结点。
    完全二叉树:只有最下面的两层结点度能够小于2,并且最下面一层的结点
    都集中在该层最左边的若干位置的二叉树。
    上图中,(a)和(b)是完全二叉树,(c)和(d)是非完全二叉树。
    给出N个数,且这N个数构成1至N的排列。现在需要你按顺序构建一棵二叉
    排序树,并按照层次遍历的方式输出它,然后判断它是否是一棵完全二叉树。
    【输入格式】
    输入文件名为binary.in。
    输入文件包含两行。第一行为一个正整数N;第二行为1至N的排列。
    【输出格式】
    输出文件名为binary.out。
    输出文件包含两行。第一行为构建出的二叉排序树的层次遍历;第二行判
    断是否是完全二叉树:若是输出yes,否则输出no。
    【输入输出样例1】
    binary.in 
    10
    7 9 8 4 6 2 10 1 5 3
    
    binary.out
    7 4 9 2 6 8 10 1 3 5
    yes
    【输入输出样例2】
    binary.in 
    5
    3 4 5 2 1
    
    binary.out
    3 2 4 1 5
    no
    【数据规模与约定】
    对于100%的数据,1≤N≤20
    View Code

    题解:基本的二叉树,读入x,然后从根节点开始,小就放左,大就放右,满了就放下一层。

    判断是否完全其实很容易,一个x个节点的树如果是完全二叉树,它的1-x号节点都是非空的,这个调试一下就可以发现。

    一开始错了其实是自己粗心,只输出了前x个节点,但是如果这颗树不是完全的,就会有未输出的情况,光荣的贡献一个wa。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define maxn 2100000
    using namespace std;
    int tree[maxn];
    int a[25],n,flg;
    
    void build(int x){
        int i=1;
        while(1){
            if(x<tree[i]){
                if(!tree[i<<1]){
                    tree[i<<1]=x;
                    break;
                }
                i<<=1;
            }
            if(x>tree[i]){
                if(!tree[i<<1|1]){
                    tree[i<<1|1]=x;
                    break;
                }
                i=i<<1|1;
            }
        }
    }
    
    int main(){
        freopen("binary.in","r",stdin);
        freopen("binary.out","w",stdout);
        scanf("%d",&n);
        flg=1;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        tree[1]=a[1];
        for(int i=2;i<=n;i++)build(a[i]);
        for(int i=1;i<=maxn;i++){
            if(!tree[i]){
                if(i<=n)
                flg=0;
            }
            else printf("%d ",tree[i]);
        }
        if(flg)printf("\nyes");
        else printf("\nno");
    }
    View Code

    2.列车调度

    【问题描述】
    有N辆列车,标记为1,2,3,…,N。它们按照一定的次序进站,站台共有K个轨
    道,轨道遵从先进先出的原则。列车进入站台内的轨道后可以等待任意时间后出
    站,且所有列车不可后退。现在要使出站的顺序变为N,N-1,N-2,…,1,询问K的
    最小值是多少。
    例如上图中进站的顺序为1,3,2,4,8,6,9,5,7,则出站的顺序变为
    9,8,7,6,5,4,3,2,1。
    【输入格式】
    输入文件名为manage.in。
    输入共2行。
    第 1 行包含1个正整数N,表示N辆列车。
    第 2 行包含N个正整数,为1至N的一个排列,表示进站次序。
    【输出格式】
    输出文件名为manage.out。
    输出共1行,包含1个整数,表示站台内轨道数K的最小值。
    【输入输出样例1】
    manage.in 
    3
    1 2 3
    
    manage.out
    3
    【输入输出样例2】
    manage.in 
    9
    1 3 2 4 8 6 9 5 7
    
    manage.out
    5
    
    【数据规模与约定】
    对于 30%的数据,N≤10;
    对于 70%的数据,N≤2000;
    对于 100%的数据,N≤100000
    View Code

    题解:这题和codevs上的拦截导弹很像,只要之前有轨道最后一辆车编号比当前的大,就把当前的车停在那。但是如果有多个符合条件,找与当前差最小的一个(这样如果再来一辆编号大的,就可以停在那些末尾较大的轨道里,保证轨道利用高效。举例:当前两个轨道,末尾分别为5,3;来了一辆编号1的车,就停在3后。因为若停在5后,若下一辆为4,则就要新开轨道造成浪费了。)。如果没有符合的轨道,则所需轨道+1。

    因为数据比较水原因,可以用以上方法暴力过,但是如果是一般情况,100000辆车,如果轨道数较大,是需要二分的。把当前所有轨道末尾放在数组里进行二分求相差最近的轨道。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    int ans,top,n,a[200005],q[200005];
    int main()
    {
        freopen("manage.in","r",stdin);
        freopen("manage.out","w",stdout);
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        int l=1,r=1;
        top=1;
        q[l]=a[1];
        for(int i=2;i<=n;i++){
            l=0;r=top;
            if(a[i]>q[top]){
                top++;
                q[top]=a[i];
                continue;
            }
            while(r-l>1){
                int m=(l+r)>>1;
                if(q[m]<a[i])l=m;
                else r=m;
            }
            q[r]=a[i];
        }
        printf("%d",top);
        return 0;
    }
    View Code

    3. 保留道路

    【问题描述】
    很久很久以前有一个国家,这个国家有N个城市,城市由1,2,3,…,N标号,
    城市间有M条双向道路,每条道路都有两个属性g和s,两个城市间可能有多条道
    路,并且可能存在将某一城市与其自身连接起来的道路。后来由于战争的原因,
    国王不得不下令减小花费从而关闭一些道路,但是必须要保证任意两个城市相互
    可达。
    道路花费的计算公式为wG*max{所有剩下道路的属性g}+wS*max{所有剩下道
    路的属性s},其中wG和wS是给定的值。国王想要在满足连通性的前提下使这个花
    费最小,现在需要你计算出这个花费。
    【输入格式】
    输入文件名为road.in。
    第一行包含两个正整数N和M。
    第二行包含两个正整数wG和wS。
    后面的M行每行描述一条道路,包含四个正整数u,v,g,s,分别表示道路连接
    的两个城市以及道路的两个属性。
    【输出格式】
    输出文件名为road.out。
    输出一个整数,表示最小花费。若无论如何不能满足连通性,输出-1。
    【输入输出样例】
    road.in
    3 3
    2 1
    1 2 10 15
    1 2 4 20
    1 3 5 1
    
    road.out
    30
    【数据规模与约定】
    对于 10%的数据,N≤10,M≤20;
    对于 30%的数据,N≤100,M≤1000;
    对于 50%的数据,N≤200,M≤5000;
    对于 100%的数据,N≤400,M≤50000,wG,wS,g,s≤1000000000
    View Code

    题解:

    这题乍一看很没思路(所以考试没做出来qaq)。但是仔细分析一下还是很有意思。

    本题的难点在于它的排序有两个参数要考虑,让人排序的时候无从下手。不过仔细考虑一下,可以发现,我们可以先从一个参数下手。

    先将所有道路按g从小到大排序,然后建立一个最小生成树有n条边,以s的值把边的编号放进数组st中,再依次把其他边加入这个数组,不难知道,新的最小值一定会从每次的n+1条边中更新而来。

    然后每次把st中最上面的点去掉,保留n条边,这样每次都从n+1条里找树,每次和ans取最小,就是答案。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define ll long long
    const int N=410;
    const int M=50010;
    int n,m,i,j,num,fu,fv;
    ll Wg,Ws;
    struct edge
    {
        int u,v,g,s;
    }a[M];
    
    ll ans=0x7fffffffffffffffLL;
    int fa[N],st[N],top;
    
    int find(int x)
    {
        return fa[x]==x?x:fa[x]=find(fa[x]);
    }
    
    int cmp(edge a,edge b){
        return a.g<b.g;
    }
    
    int main(){
        freopen("road.in","r",stdin);
        freopen("road.out","w",stdout);
        scanf("%d%d",&n,&m);
        scanf("%d%d",&Wg,&Ws);
        for(i=1;i<=m;i++){
            scanf("%d%d%d%d",&a[i].u,&a[i].v,&a[i].g,&a[i].s);
        }
        sort(a+1,a+m+1,cmp);
        top=0;
        for(i=1;i<=m;i++){
            for(j=1;j<=n;j++)fa[j]=j;
            for(j=top;j>=1;j--){
                if(a[st[j]].s>a[i].s){
                    st[j+1]=st[j];
                }
                else break;
            }
            top++;
            st[j+1]=i;
            num=0;
            for(j=1;j<=top;j++){
                fu=find(a[st[j]].u);fv=find(a[st[j]].v);
                if (fu!=fv)
                {
                    fa[fu]=fv;
                    st[++num]=st[j];
                }
            }
            if (num==n-1)
                ans=min(ans,Wg*a[i].g+Ws*a[st[num]].s);
            top=num;
        }
        if (ans==0x7fffffffffffffffLL)printf("-1\n");
        else printf("%I64d\n",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    Java系列教程-Spring 教程目录
    python中如何给散点图上面的特定点做标记
    OpenCV:Python下OpenCV安装和入门最强详细攻略
    如何实现一个 windows 桌面动态壁纸
    学习C/C++的简单方法
    手眼标定
    python合并多个txt文件
    python qq发消息
    python获取当前天气情况
    程序代写、毕业设计
  • 原文地址:https://www.cnblogs.com/Requiescat/p/7397102.html
Copyright © 2020-2023  润新知