• 中国石油大学天梯赛真题模拟第一场


    7-10 排座位 (25 分)

    布置宴席最微妙的事情,就是给前来参宴的各位宾客安排座位。无论如何,总不能把两个死对头排到同一张宴会桌旁!这个艰巨任务现在就交给你,对任何一对客人,请编写程序告诉主人他们是否能被安排同席。

    输入格式:

    输入第一行给出3个正整数:N≤100),即前来参宴的宾客总人数,则这些人从1到N编号;M为已知两两宾客之间的关系数;K为查询的条数。随后M行,每行给出一对宾客之间的关系,格式为:宾客1 宾客2 关系,其中关系为1表示是朋友,-1表示是死对头。注意两个人不可能既是朋友又是敌人。最后K行,每行给出一对需要查询的宾客编号。

    这里假设朋友的朋友也是朋友。但敌人的敌人并不一定就是朋友,朋友的敌人也不一定是敌人。只有单纯直接的敌对关系才是绝对不能同席的。

    输出格式:

    对每个查询输出一行结果:如果两位宾客之间是朋友,且没有敌对关系,则输出No problem;如果他们之间并不是朋友,但也不敌对,则输出OK;如果他们之间有敌对,然而也有共同的朋友,则输出OK but...;如果他们之间只有敌对关系,则输出No way

    输入样例:

    7 8 4
    5 6 1
    2 7 -1
    1 3 1
    3 4 1
    6 7 -1
    1 2 1
    1 4 1
    2 3 -1
    3 4
    5 7
    2 3
    7 2
    

    输出样例:

    No problem
    OK
    OK but...
    No way


    很迷的题面,令人头秃。训练的时候有一个点没过(因为当时开始写了-1的最短路,最外层循环只for到2……我也不知道当时怎么想的

    #include "bits/stdc++.h"
    
    using namespace std;
    const int maxn = 200;
    
    int mp[maxn][maxn], fri[maxn][maxn], ene[maxn][maxn];
    
    int main() {
        int n, m, k;
        cin >> n >> m >> k;
        int a, b, c;
        for (int i = 1; i <= m; i++) {
            cin >> a >> b >> c;
            mp[a][b] = c;
            mp[b][a] = c;
            if (c == 1) {
                fri[a][b] = c;
                fri[b][a] = c;
            } else {
                ene[a][b] = c;
                ene[b][a] = b;
            }
        }
        for (int k = 1; k <= n; k++) {
            for (int i = 1; i <= n; i++) {
                for (int j = 1; j <= n; j++) {
                    if (fri[i][k] == 1 && fri[k][j] == 1) {
                        fri[i][j] = 1;
                    }
                }
            }
        }
        while (k--) {
            cin >> a >> b;
            if (mp[a][b] == -1 && fri[a][b] == 0) {
                cout << "No way" << endl;
            } else if (mp[a][b] == -1 && fri[a][b] == 1) {
                cout << "OK but..." << endl;
            } else if (mp[a][b] == 0) {
                cout << "OK" << endl;
            } else cout << "No problem" << endl;
        }
        return 0;
    }
    View Code
    
    
    玩转二叉树 (25 分)

    给定一棵二叉树的中序遍历和前序遍历,请你先将树做个镜面反转,再输出反转后的层序遍历的序列。所谓镜面反转,是指将所有非叶结点的左右孩子对换。这里假设键值都是互不相等的正整数。

    输入格式:

    输入第一行给出一个正整数N≤30),是二叉树中结点的个数。第二行给出其中序遍历序列。第三行给出其前序遍历序列。数字间以空格分隔。

    输出格式:

    在一行中输出该树反转后的层序遍历的序列。数字间以1个空格分隔,行首尾不得有多余空格。

    输入样例:

    7
    1 2 3 4 5 6 7
    4 1 3 2 6 5 7
    

    输出样例:

    4 6 1 7 5 3 2
    用递归可以从一个树得到其遍历序列,那么从遍历序列得到树将其递归反过来就行。反转操作可以忽略,在bfs的时候先插入右儿子就可以了
    #include "bits/stdc++.h"
    
    using namespace std;
    
    const int maxn = 100;
    int dlr[maxn], ldr[maxn];
    int n;
    typedef struct node {
        int val;
        node *l, *r;
    } *tree;
    tree root = NULL;
    
    void build(tree &t, int start, int lasttime, int len) {
        if (len <= 0) {
            t = NULL;
            return;
        }
        int now;
        t = (tree) malloc(sizeof(node));
        t->val = dlr[start];
        for (int i = 0; i < n; i++) {
            if (ldr[i] == dlr[start]) {
                now = i;
                break;
            }
        }
        int lenl = now - lasttime;
        build(t->l, start + 1, lasttime, lenl);
        int lenr = len - 1 - lenl;
        build(t->r, start + lenl + 1, now + 1, lenr);
    }
    
    void bfs() {
        queue<tree> q;
        q.push(root);
        int flag = 0;
        tree temp;
        while (!q.empty()) {
            if (flag) printf(" ");
            flag = 1;
            temp = q.front();
            q.pop();
            cout << temp->val;
            if (temp->r != NULL) q.push(temp->r);
            if (temp->l != NULL) q.push(temp->l);
        }
    }
    
    int main() {
        cin >> n;
        for (int i = 0; i < n; i++) {
            cin >> ldr[i];
        }
        for (int i = 0; i < n; i++) {
            cin >> dlr[i];
        }
        build(root, 0, 0, n);
        bfs();
        return 0;
    }
    View Code
    
    
    关于堆的判断 (25 分)

    将一系列给定数字顺序插入一个初始为空的小顶堆H[]。随后判断一系列相关命题是否为真。命题分下列几种:

    • x is the rootx是根结点;
    • x and y are siblingsxy是兄弟结点;
    • x is the parent of yxy的父结点;
    • x is a child of yxy的一个子结点。

    输入格式:

    每组测试第1行包含2个正整数N≤ 1000)和M≤ 20),分别是插入元素的个数、以及需要判断的命题数。下一行给出区间[10000,10000]内的N个要被插入一个初始为空的小顶堆的整数。之后M行,每行给出一个命题。题目保证命题中的结点键值都是存在的。

    输出格式:

    对输入的每个命题,如果其为真,则在一行中输出T,否则输出F

    输入样例:

    5 4
    46 23 26 24 10
    24 is the root
    26 and 23 are siblings
    46 is the parent of 23
    23 is a child of 10
    

    输出样例:

    F
    T
    F
    T
    判断两个节点是兄弟只要判断他们的父亲是同一个节点就可以了,比赛的时候写了判断他们相邻且一个在奇数节点一个在偶数节点。。。。
    // make_heap(heap + 1, heap + 1 + i, greater<int>());
    //c++自带的建树函数,默认建大根堆
    #include "bits/stdc++.h"
    
    using namespace std;
    const int maxn = 1e5;
    const int base = 11000;
    int heap[maxn];
    int ver[maxn];
    int n, m;
    
    void up(int p) {
        while (p > 1) {
            if (heap[p] < heap[p / 2]) {
                swap(heap[p], heap[p / 2]);
                p /= 2;
            } else break;
        }
    }
    
    
    int main() {
        cin >> n >> m;
        int x;
        for (int i = 1; i <= n; i++) {
            cin >> x;
            heap[i] = x;
            up(i);
           // make_heap(heap + 1, heap + 1 + i, greater<int>());
           //c++自带的建树函数,默认建大根堆
        }
        for (int i = 1; i <= n; i++) {
            ver[heap[i] + base] = i;//去掉负数
        }
        char str[10000];
        int a, b;
        while (m--) {
            scanf("%d", &a);
            scanf("%s", str);
            if (str[0] == 'a') {
                scanf("%d", &b);
                scanf("%s", str);
                scanf("%s", str);
                if (ver[a + base] / 2 == ver[b + base] / 2) {//a和b是兄弟
                    cout << "T" << endl;
                } else cout << "F" << endl;
            } else {
                scanf("%s", str);
                if (str[0] == 'a') {
                    scanf("%s", str);
                    scanf("%s", str);
                    scanf("%d", &b);
                    if (ver[a + base] / 2 == ver[b + base])//a是b的儿子
                        cout << "T" << endl;
                    else
                        cout << "F" << endl;
                } else {
                    scanf("%s", str);
                    if (str[0] == 'r') {//a是树根
                        if (heap[1] == a)
                            cout << "T" << endl;
                        else cout << "F" << endl;
    
                    } else {
                        scanf("%s", str);
    
                        scanf("%d", &b);
                        if (ver[a + base] == ver[b + base] / 2)//a是b的父亲
                            cout << "T" << endl;
                        else cout << "F" << endl;
    
                    }
                }
            }
        }
        return 0;
    }
    View Code
    
    
    天梯地图 (30 分)
    
    

    本题要求你实现一个天梯赛专属在线地图,队员输入自己学校所在地和赛场地点后,该地图应该推荐两条路线:一条是最快到达路线;一条是最短距离的路线。题目保证对任意的查询请求,地图上都至少存在一条可达路线。

    输入格式:

    输入在第一行给出两个正整数N(2 ≤ N ≤ 500)和M,分别为地图中所有标记地点的个数和连接地点的道路条数。随后M行,每行按如下格式给出一条道路的信息:

    V1 V2 one-way length time
    

    其中V1V2是道路的两个端点的编号(从0到N-1);如果该道路是从V1V2的单行线,则one-way为1,否则为0;length是道路的长度;time是通过该路所需要的时间。最后给出一对起点和终点的编号。

    输出格式:

    首先按下列格式输出最快到达的时间T和用节点编号表示的路线:

    Time = T: 起点 => 节点1 => ... => 终点
    

    然后在下一行按下列格式输出最短距离D和用节点编号表示的路线:

    Distance = D: 起点 => 节点1 => ... => 终点
    

    如果最快到达路线不唯一,则输出几条最快路线中最短的那条,题目保证这条路线是唯一的。而如果最短距离的路线不唯一,则输出途径节点数最少的那条,题目保证这条路线是唯一的。

    如果这两条路线是完全一样的,则按下列格式输出:

    Time = T; Distance = D: 起点 => 节点1 => ... => 终点
    

    输入样例1:

    10 15
    0 1 0 1 1
    8 0 0 1 1
    4 8 1 1 1
    5 4 0 2 3
    5 9 1 1 4
    0 6 0 1 1
    7 3 1 1 2
    8 3 1 1 2
    2 5 0 2 2
    2 1 1 1 1
    1 5 0 1 3
    1 4 0 1 1
    9 7 1 1 3
    3 1 0 2 5
    6 3 1 2 1
    5 3
    

    输出样例1:

    Time = 6: 5 => 4 => 8 => 3
    Distance = 3: 5 => 1 => 3
    

    输入样例2:

    7 9
    0 4 1 1 1
    1 6 1 3 1
    2 6 1 1 1
    2 5 1 2 2
    3 0 0 1 1
    3 1 1 3 1
    3 2 1 2 1
    4 5 0 2 2
    6 5 1 2 1
    3 5
    

    输出样例2:

    Time = 3; Distance = 4: 3 => 2 => 5
    读题读题读题,比赛时读题要尽量的慢,准,稳。
    #include "bits/stdc++.h"
    
    using namespace std;
    const int maxn = 600;
    int timemap[maxn][maxn], lenmap[maxn][maxn];
    int lendist[maxn], lt[maxn], tl[maxn], timedist[maxn], timepre[maxn], timevis[maxn];
    int lenpre[maxn], lenvis[maxn];
    int n, m, s, d;
    vector<int> ans1, ans2;
    
    bool check() {
        if (ans1.size() != ans2.size()) return false;
        for (int i = 0; i < ans1.size(); i++) {
            if (ans1[i] != ans2[i]) return false;
        }
        return true;
    }
    
    void dij1() {
        memset(timedist, 0x3f, sizeof(timedist));
        memset(timevis, 0, sizeof(timevis));
        memset(timepre, -1, sizeof(timepre));
        memset(lendist, 0x3f, sizeof(lendist));
        memset(lenvis, 0, sizeof(lenvis));
        memset(lenpre, -1, sizeof(lenpre));
        memset(lt, 0x3f, sizeof(lt));
        memset(tl, 0x3f, sizeof(lt));
        timedist[s] = 0;
        lendist[s] = 0;
        lt[s] = 1;
        tl[s] = 0;
        for (int i = 1; i < n; i++) {
            int x = -1;
            for (int j = 0; j < n; j++) {
                if (!timevis[j] && (x == -1 || timedist[j] < timedist[x])) x = j;
            }
            timevis[x] = 1;
            for (int j = 0; j < n; j++) {
                if (timedist[x] + timemap[x][j] < timedist[j]) {
                    timedist[j] = timedist[x] + timemap[x][j];
                    tl[j] = tl[x] + lenmap[x][j];
                    timepre[j] = x;
                } else if (timedist[x] + timemap[x][j] == timedist[j] &&
                           tl[x] + lenmap[x][j] < tl[j]) {
                    tl[j] = tl[x] + lenmap[x][j];
                    timepre[j] = x;
                }
            }
    
            x = -1;
            for (int j = 0; j < n; j++) {
                if (!lenvis[j] && (x == -1 || lendist[j] < lendist[x])) x = j;
            }
            lenvis[x] = 1;
            for (int j = 0; j < n; j++) {
                if (lendist[x] + lenmap[x][j] < lendist[j]) {
                    lendist[j] = lendist[x] + lenmap[x][j];
                    lenpre[j] = x;
                    lt[j] = lt[x] + 1;
                } else if (lendist[x] + lenmap[x][j] == lendist[j]
                           && lt[x] + 1 < lt[j]) {
                    lenpre[j] = x;
                    lt[j] = lt[x] + 1;
                }
            }
        }
    
        ans1.push_back(d);
        int x = timepre[d];
        while (x != -1) {
            ans1.push_back(x);
            x = timepre[x];
        }
    
        ans2.push_back(d);
        x = lenpre[d];
        while (x != -1) {
            ans2.push_back(x);
            x = lenpre[x];
        }
    
        if (check()) {
            printf("Time = %d; Distance = %d: ", timedist[d], lendist[d]);
            int flag = 0;
            for (int i = ans1.size() - 1; i >= 0; i--) {
                if (flag) printf(" => ");
                flag = 1;
                printf("%d", ans1[i]);
            }
            printf("
    ");
            return;
        }
    
        printf("Time = %d: ", timedist[d]);
        int flag = 0;
        for (int i = ans1.size() - 1; i >= 0; i--) {
            if (flag) printf(" => ");
            flag = 1;
            printf("%d", ans1[i]);
        }
        printf("
    ");
    
        printf("Distance = %d: ", lendist[d]);
        flag = 0;
        for (int i = ans2.size() - 1; i >= 0; i--) {
            if (flag) printf(" => ");
            flag = 1;
            printf("%d", ans2[i]);
        }
        printf("
    ");
    }
    
    
    int main() {
        //freopen("input.txt", "r", stdin);
        memset(lenmap, 0x3f, sizeof(lenmap));
        memset(timemap, 0x3f, sizeof(timemap));
        cin >> n >> m;
        int a, b, c, dd, e;
        for (int i = 0; i < m; i++) {
            cin >> a >> b >> c >> dd >> e;
            if (!c) {
                timemap[b][a] = e;
                lenmap[b][a] = dd;
            }
            timemap[a][b] = e;
            lenmap[a][b] = dd;
        }
        cin >> s >> d;
        dij1();
        return 0;
    }
    又臭又长
    
    
    
    喊山 (30 分) 

    喊山,是人双手围在嘴边成喇叭状,对着远方高山发出“喂—喂喂—喂喂喂……”的呼唤。呼唤声通过空气的传递,回荡于深谷之间,传送到人们耳中,发出约定俗成的“讯号”,达到声讯传递交流的目的。原来它是彝族先民用来求援呼救的“讯号”,慢慢地人们在生活实践中发现了它的实用价值,便把它作为一种交流工具世代传袭使用。(图文摘自:http://news.xrxxw.com/newsshow-8018.html)

    
    

    
    

    一个山头呼喊的声音可以被临近的山头同时听到。题目假设每个山头最多有两个能听到它的临近山头。给定任意一个发出原始信号的山头,本题请你找出这个信号最远能传达到的地方。

    
    

    输入格式:

    
    

    输入第一行给出3个正整数nmk,其中n≤10000)是总的山头数(于是假设每个山头从1到n编号)。接下来的m行,每行给出2个不超过n的正整数,数字间用空格分开,分别代表可以听到彼此的两个山头的编号。这里保证每一对山头只被输入一次,不会有重复的关系输入。最后一行给出k≤10)个不超过n的正整数,数字间用空格分开,代表需要查询的山头的编号。

    
    

    输出格式:

    
    

    依次对于输入中的每个被查询的山头,在一行中输出其发出的呼喊能够连锁传达到的最远的那个山头。注意:被输出的首先必须是被查询的个山头能连锁传到的。若这样的山头不只一个,则输出编号最小的那个。若此山头的呼喊无法传到任何其他山头,则输出0。

    
    

    输入样例:

    
    
    7 5 4
    1 2
    2 3
    3 1
    4 5
    5 6
    1 4 5 7
    
    
    

    输出样例:

    
    
    2
    6
    4
    0
     
    简单bfs

    #include "bits/stdc++.h"
    
    using namespace std;
    const int maxn = 10010;
    vector<int> e[maxn];
    struct node {
        int pos, dis;
    };
    int n, m, k;
    int vis[maxn];
    int ans, dis;
    
    void bfs(int x) {
        queue<node> q;
        node temp, tt;
        temp.dis = 0;
        temp.pos = x;
        vis[x] = 1;
        q.push(temp);
        while (!q.empty()) {
            temp = q.front();
            q.pop();
            if (temp.dis > dis) {
                dis = temp.dis;
                ans = temp.pos;
            } else if (temp.dis == dis && temp.pos < ans) {
                ans = temp.pos;
            }
            for (auto p:e[temp.pos]) {
                if (!vis[p]) {
                    vis[p] = 1;
                    tt.pos = p;
                    tt.dis = temp.dis + 1;
                    q.push(tt);
                }
            }
        }
    }
    
    int main() {
        cin >> n >> m >> k;
        int a, b;
        for (int i = 0; i < m; i++) {
            cin >> a >> b;
            e[a].push_back(b);
            e[b].push_back(a);
        }
        while (k--) {
            cin >> a;
            ans = 0x3f3f3f3f;
            dis = -0x3f3f3f3f;
            bfs(a);
            cout << (ans == a ? 0 : ans) << endl;
            memset(vis, 0, sizeof(vis));
        }
        return 0;
    }
    View Code
    长城 (30 分)

    正如我们所知,中国古代长城的建造是为了抵御外敌入侵。在长城上,建造了许多烽火台。每个烽火台都监视着一个特定的地区范围。一旦某个地区有外敌入侵,值守在对应烽火台上的士兵就会将敌情通报给周围的烽火台,并迅速接力地传递到总部。

    现在如图1所示,若水平为南北方向、垂直为海拔高度方向,假设长城就是依次相联的一系列线段,而且在此范围内的任一垂直线与这些线段有且仅有唯一的交点。

    图 1

    进一步地,假设烽火台只能建造在线段的端点处。我们认为烽火台本身是没有高度的,每个烽火台只负责向北方(图1中向左)瞭望,而且一旦有外敌入侵,只要敌人与烽火台之间未被山体遮挡,哨兵就会立即察觉。当然,按照这一军规,对于南侧的敌情各烽火台并不负责任。一旦哨兵发现敌情,他就会立即以狼烟或烽火的形式,向其南方的烽火台传递警报,直到位于最南侧的总部。

    以图2中的长城为例,负责守卫的四个烽火台用蓝白圆点示意,最南侧的总部用红色圆点示意。如果红色星形标示的地方出现敌情,将被哨兵们发现并沿红色折线将警报传递到总部。当然,就这个例子而言只需两个烽火台的协作,但其他位置的敌情可能需要更多。

    然而反过来,即便这里的4个烽火台全部参与,依然有不能覆盖的(黄色)区域。

    图 2

    另外,为避免歧义,我们在这里约定,与某个烽火台的视线刚好相切的区域都认为可以被该烽火台所监视。以图3中的长城为例,若A、B、C、D点均共线,且在D点设置一处烽火台,则A、B、C以及线段BC上的任何一点都在该烽火台的监视范围之内。

    图 3

    好了,倘若你是秦始皇的太尉,为不致出现更多孟姜女式的悲剧,如何在保证长城安全的前提下,使消耗的民力(建造的烽火台)最少呢?

    输入格式:

    输入在第一行给出一个正整数N(3 ≤ N 105​​),即刻画长城边缘的折线顶点(含起点和终点)数。随后N行,每行给出一个顶点的xy坐标,其间以空格分隔。注意顶点从南到北依次给出,第一个顶点为总部所在位置。坐标为区间[109​​,109​​)内的整数,且没有重合点。

    输出格式:

    在一行中输出所需建造烽火台(不含总部)的最少数目。

    输入样例:

    10
    67 32
    48 -49
    32 53
    22 -44
    19 22
    11 40
    10 -65
    -1 -23
    -3 31
    -7 59
    

    输出样例:

    2

    求凸包的思想,利用向量叉积判断,如果两个点之间隔着一个上凸(角abc),则从a观测不到c,需在b建一个瞭望台
     
    #include "bits/stdc++.h"
    
    using namespace std;
    const int maxn = 1e5+100;
    struct point {
        int x, y;
        int pos;
    } st[maxn];
    int vis[maxn];
    
    bool check(point a, point b, point c) {
        return 1ll * (b.x - a.x) * (c.y - b.y) - (c.x - b.x) * (b.y - a.y) <= 0;
    }
    
    int main() {
        int n;
        cin >> n;
        point pos;
        int s = 0;
        for (int i = 0; i < n; i++) {
            cin >> pos.x >> pos.y;
            pos.pos = i;
            if (s >= 1) {
                while (s >= 2 && check(st[s - 2], st[s - 1], pos))
                    s--;
                vis[st[s - 1].pos] = 1;
            }
            st[s++] = pos;
        }
        int ans = 0;
        for (int i = 1; i <= n; i++) {
            if (vis[i])ans++;
        }
        cout << ans << endl;
        return 0;
    }
    View Code

     

  • 相关阅读:
    GRUB2 分析 (三)
    GRUB2 分析 (二)
    快速填充像素的方法
    GRUB2 分析 (一)
    自制Linux映像和发行版Robomind
    为MarS Board安装无线网卡Linux驱动
    alsa音频播放过程中的基本概念
    常见Soc平台图形内存管理学习笔记
    snprintf笔记
    linux命令行配置wifi连接并通过ssh代理开启socks代理
  • 原文地址:https://www.cnblogs.com/albert-biu/p/10534087.html
Copyright © 2020-2023  润新知