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

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

这么一场下来是真的累。。。从头敲到尾。感觉里面的题目都比较基础,一些基础的数据读取和一些比较基础的数据结构。但是也踩了不少坑。。。

7-1 正整数A+B (15 分)

题的目标很简单,就是求两个正整数A和B的和,其中A和B都在区间[1,1000]。稍微有点麻烦的是,输入并不保证是两个正整数。

输入格式:
输入在一行给出A和B,其间以空格分开。问题是A和B不一定是满足要求的正整数,有时候可能是超出范围的数字、负数、带小数点的实数、甚至是一堆乱码。

注意:我们把输入中出现的第1个空格认为是A和B的分隔。题目保证至少存在一个空格,并且B不是一个空字符串。

输出格式:
如果输入的确是两个正整数,则按格式A + B = 和输出。如果某个输入不合要求,则在相应位置输出?,显然此时和也是?。

输入样例1:
123 456
输出样例1:
123 + 456 = 579
输入样例2:
22. 18
输出样例2:
? + 18 = ?
输入样例3:
-100 blabla bla...33
输出样例3:
? + ? = ?
正整数A+B

一个小坑,最后切水题的时候读题不清,没有看到有可能是超出范围的数字。

第二个就是cin与scanf("%s")读入字符串时,不会读入空格,需要在读入第一个字符串后,用getchar()读入第一个空格,然后用getline读取剩下的所有数据。

#include "bits/stdc++.h"

using namespace std;
const int maxn = 1e5;

int main() {
    char str1[maxn], str2[maxn];
    cin >> str1;//cin与scanf(“%s”)都不会读入空格,所以下面要用getchar读第一个空格,不然空格就会让后面的getlin读到
    getchar();
    cin.getline(str2, maxn);
    int flag1 = 0, flag2 = 0;
    int len1 = strlen(str1);
    int len2 = strlen(str2);
    long long val1 = 0, val2 = 0;
    for (int i = 0; i < len1; i++) {
        val1 = val1 * 10 + str1[i] - '0';
        if (!(str1[i] >= '0' && str1[i] <= '9'))flag1 = 1;
    }
    for (int i = 0; i < len2; i++) {
        val2 = val2 * 10 + str2[i] - '0';
        if (!(str2[i] >= '0' && str2[i] <= '9'))flag2 = 1;
    }
    if (!flag1 && val1 >= 1 && val1 <= 1000) printf("%lld ", val1);
    else printf("? ");
    printf("+ ");
    if (!flag2 && val2 >= 1 && val2 <= 1000) printf("%lld ", val2);
    else printf("? ");
    printf("= ");
    if (!flag1 && !flag2 && val1 >= 1 && val1 <= 1000 && val2 >= 1 && val2 <= 1000) {
        printf("%lld\n", val1 + val2);
    } else {
        printf("?\n");
    }
    return 0;
}
View Code

 

7-4 判断素数 (10 分)

本题的目标很简单,就是判断一个给定的正整数是否素数。

输入格式:
输入在第一行给出一个正整数N(≤ 10),随后N行,每行给出一个小于2
​31
​​ 的需要判断的正整数。

输出格式:
对每个需要判断的正整数,如果它是素数,则在一行中输出Yes,否则输出No。

输入样例:
2
11
111
输出样例:
Yes
No
7-4 判断素数

也不知道当时在想些什么,看见231就想米勒罗宾,然后觉得不会写米勒罗宾,就直接交了个for到n的,连根号n都给忘了。

玄学卡常,i*i过不了,把sqrt写到for里就能过,sqrt比*快么。。。

* 1不是素数,素数从2开始

//没过的代码,tle
#include "bits/stdc++.h"

using namespace std;

bool check(int temp) {
    for (int i = 2; i * i <= temp; i++) {
        if (temp % i == 0) {
            return false;
        }
    }
    return true;
}

int main() {
    int n;
    cin >> n;
    int temp;
    for (int i = 0; i < n; i++) {
        cin >> temp;
        if (check(temp)) {
            cout << "Yes" << endl;
        } else {
            cout << "No" << endl;
        }
    }
    return 0;
}

//过了的
#include "bits/stdc++.h"

using namespace std;

bool check(int temp) {
    int to = sqrt(temp);
    if (temp == 1) return false;//特判1不是质数
    for (int i = 2; i <= to; i++) {//优化常数,被卡常了
        if (temp % i == 0) {
            return false;
        }
    }
    return true;
}

int main() {
    int n;
    cin >> n;
    int temp;
    for (int i = 0; i < n; i++) {
        cin >> temp;
        if (check(temp)) {
            cout << "Yes" << endl;
        } else {
            cout << "No" << endl;
        }
    }
    return 0;
}
View Code
 
7-9 红色警报 (25 分)
战争中保持各个城市间的连通性非常重要。本题要求你编写一个报警程序,当失去一个城市导致国家被分裂为多个无法连通的区域时,就发出红色警报。注意:若该国本来就不完全连通,是分裂的k个区域,而失去一个城市并不改变其他城市之间的连通性,则不要发出警报。

输入格式:
输入在第一行给出两个整数N(0 < N ≤ 500)和M(≤ 5000),分别为城市个数(于是默认城市从0到N-1编号)和连接两城市的通路条数。随后M行,每行给出一条通路所连接的两个城市的编号,其间以1个空格分隔。在城市信息之后给出被攻占的信息,即一个正整数K和随后的K个被攻占的城市的编号。

注意:输入保证给出的被攻占的城市编号都是合法的且无重复,但并不保证给出的通路没有重复。

输出格式:
对每个被攻占的城市,如果它会改变整个国家的连通性,则输出Red Alert: City k is lost!,其中k是该城市的编号;否则只输出City k is lost.即可。如果该国失去了最后一个城市,则增加一行输出Game Over.。

输入样例:
5 4
0 1
1 3
3 0
0 4
5
1 2 0 4 3
输出样例:
City 1 is lost.
City 2 is lost.
Red Alert: City 0 is lost!
City 4 is lost.
City 3 is lost.
Game Over.
7-9 红色警报 (25 分)

太菜了,读完题就感觉不会写,然后就去写后面的题了。

实际很简单,就是一个dfs,只是以前没搞过联通块,一下看见不知道该怎么办。

就是在删除一个城市后用dfs计算一下联通块个数,如果联通块个数增多了,那就是国家连通性被改变了

#include "bits/stdc++.h"

using namespace std;
const int maxn = 600;
int n, m;
int vis[maxn];
vector<int> e[maxn];
int killed[maxn], killednum = 0;

void dfs(int now) {
    vis[now] = 1;
    for (auto p:e[now]) {
        if (!vis[p] && !killed[p]) {
            dfs(p);
        }
    }
}

int check() {
    int cnt = 0;
    memset(vis, 0, sizeof(vis));
    for (int i = 0; i < n; i++) {
        if (!vis[i] && !killed[i]) {
            dfs(i);
            cnt++;
        }
    }
    return cnt;
}

int main() {
    cin >> n >> m;
    int a, b;
    for (int i = 0; i < m; i++) {
        cin >> a >> b;
        e[a].push_back(b);
        e[b].push_back(a);
    }
    int town = check();
    int x, temp;
    cin >> m;
    while (m--) {
        cin >> x;
        killed[x] = 1;
        killednum++;
        temp = check();

        if (temp > town) {
            printf("Red Alert: City %d is lost!\n", x);
        } else if (temp <= town) {
            printf("City %d is lost.\n", x);
        }
        if (killednum == n) {
            printf("Game Over.\n");
            return 0;
        }
        town = temp;
    }
    return 0;
}
View Code

 

 7-12 愿天下有情人都是失散多年的兄妹 (25 分)

呵呵。大家都知道五服以内不得通婚,即两个人最近的共同祖先如果在五代以内(即本人、父母、祖父母、曾祖父母、高祖父母)则不可通婚。本题就请你帮助一对有情人判断一下,他们究竟是否可以成婚?

输入格式:
输入第一行给出一个正整数N(2 ≤ N ≤104
​​ ),随后N行,每行按以下格式给出一个人的信息:

本人ID 性别 父亲ID 母亲ID
其中ID是5位数字,每人不同;性别M代表男性、F代表女性。如果某人的父亲或母亲已经不可考,则相应的ID位置上标记为-1。

接下来给出一个正整数K,随后K行,每行给出一对有情人的ID,其间以空格分隔。

注意:题目保证两个人是同辈,每人只有一个性别,并且血缘关系网中没有乱伦或隔辈成婚的情况。

输出格式:
对每一对有情人,判断他们的关系是否可以通婚:如果两人是同性,输出Never Mind;如果是异性并且关系出了五服,输出Yes;如果异性关系未出五服,输出No。

输入样例:
24
00001 M 01111 -1
00002 F 02222 03333
00003 M 02222 03333
00004 F 04444 03333
00005 M 04444 05555
00006 F 04444 05555
00007 F 06666 07777
00008 M 06666 07777
00009 M 00001 00002
00010 M 00003 00006
00011 F 00005 00007
00012 F 00008 08888
00013 F 00009 00011
00014 M 00010 09999
00015 M 00010 09999
00016 M 10000 00012
00017 F -1 00012
00018 F 11000 00013
00019 F 11100 00018
00020 F 00015 11110
00021 M 11100 00020
00022 M 00016 -1
00023 M 10012 00017
00024 M 00022 10013
9
00021 00024
00019 00024
00011 00012
00022 00018
00001 00004
00013 00016
00017 00015
00019 00021
00010 00011
输出样例:
Never Mind
Yes
Never Mind
No
Yes
No
Yes
No
No
7-12 愿天下有情人都是失散多年的兄妹 (25 分)

写的时候只过了两个点,结束后搜题解才发现,在输入一个人的父母时,他父母的性别是已知的,要为其性别赋值。一开始所有人的父母都初始化为-1

#include "bits/stdc++.h"

using namespace std;

const int maxn = 1e5 + 100;

int n;
struct node {
    int id, faid, maid;
    char sex;
} e[maxn];
vector<int> q;
int vis[maxn];
int have[maxn];

void dfs1(int id, int s) {
    if (s >= 4) return;


//    cout << e[id].faid << endl;
//    cout << e[id].maid << endl;
    if (e[id].faid != -1) {
        q.push_back(e[id].faid);
        vis[e[id].faid] = 1;

        if (have[e[id].faid])
            dfs1(e[id].faid, s + 1);
    }
    if (e[id].maid != -1) {
        q.push_back(e[id].maid);
        vis[e[id].maid] = 1;
        if (have[e[id].maid])
            dfs1(e[id].maid, s + 1);
    }
}

bool dfs2(int id, int s) {
    if (s >= 4) return false;
    if (vis[e[id].faid] || vis[e[id].maid]) return true;
    if (e[id].faid != -1 && have[e[id].faid])
        if (dfs2(e[id].faid, s + 1)) return true;
    if (e[id].maid != -1 && have[e[id].maid])
        if (dfs2(e[id].maid, s + 1))
            return true;
    return false;
}

int main() {
    //freopen("input.txt", "r", stdin);
    cin >> n;
    int id;
    int maxx = 0;
    for (int i = 0; i < maxn; i++) {
        e[i].faid = -1;
        e[i].maid = -1;
    }
    for (int i = 1; i <= n; i++) {
        cin >> id;
        have[id] = 1;
        cin >> e[id].sex >> e[id].faid >> e[id].maid;
        e[e[id].faid].sex = 'M';
        e[e[id].maid].sex = 'F';
        maxx = max(id, maxx);
    }
    int m;
    cin >> m;
    int a, b;
    while (m--) {
        cin >> a >> b;
        if (e[a].sex == e[b].sex) {
            cout << "Never Mind" << endl;
        } else {
            for (auto p:q) {
                vis[p] = 0;
            }
            q.clear();
            dfs1(a, 0);
            if (dfs2(b, 0)) {
                cout << "No" << endl;
            } else {
                cout << "Yes" << endl;
            }
        }
    }
    return 0;
}
View Code

 

7-13 是否完全二叉搜索树 (30 分)
 
将一系列给定数字顺序插入一个初始为空的二叉搜索树(定义为左子树键值大,右子树键值小),你需要判断最后的树是否一棵完全二叉树,并且给出其层序遍历的结果。

输入格式:
输入第一行给出一个不超过20的正整数N;第二行给出N个互不相同的正整数,其间以空格分隔。

输出格式:
将输入的N个正整数顺序插入一个初始为空的二叉搜索树。在第一行中输出结果树的层序遍历结果,数字间以1个空格分隔,行的首尾不得有多余空格。第二行输出YES,如果该树是完全二叉树;否则输出NO。

输入样例1:
9
38 45 42 24 58 30 67 12 51
输出样例1:
38 45 24 58 42 30 12 67 51
YES
输入样例2:
8
38 24 12 45 58 67 42 51
输出样例2:
38 45 24 58 42 12 67 51
NO
7-13 是否完全二叉搜索树 (30 分)

二叉查找树英语:Binary Search Tree),也称为二叉搜索树有序二叉树ordered binary tree)或排序二叉树sorted binary tree),是指一棵空树或者具有下列性质的二叉树:

  1. 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
  2. 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
  3. 任意节点的左、右子树也分别为二叉查找树;
  4. 没有键值相等的节点。

判断一棵树是否是完全二叉树的思路:
1、如果树为空,则直接返回错。
2、如果树不为空:层序遍历二叉树。
3、如果一个结点左右孩子都不为空,将其左右孩子入队列;
4、如果遇到一个结点,左孩子为空,右孩子不为空,则该树一定不是完全二叉树;
5、如果遇到一个结点,左孩子不为空,右孩子为空;或者左右孩子都为空;则该节点之后 的队列中的结点都为叶子节点;该树才是完全二叉树,否则就不是完全二叉树;

一开始判断完全二叉树时漏掉了第五点,。。后来又漏掉了左右孩子为空则后面只有叶子结点。

#include "bits/stdc++.h"

using namespace std;
struct node {
    int l, r;
    int val;
} a[100];
int tot = 0;
int root;
int NO = 0;

int New(int val) {
    a[++tot].val = val;
    a[tot].l = 0;
    a[tot].r = 0;
    return tot;
}

void insert(int &p, int val) {
    if (p == 0) {
        p = New(val);
        return;
    }
    if(a[p].val==val) return;
    if (val > a[p].val) insert(a[p].l, val);
    else insert(a[p].r, val);
}

void bfs() {
    queue q;
    q.push(a[1]);
    node temp;
    int flag = 0;
    int isson = 0;
    while (!q.empty()) {
        temp = q.front();
        q.pop();
        if (flag) printf(" ");
        flag = 1;
        printf("%d", temp.val);
        if (temp.l) q.push(a[temp.l]);
        if (temp.r) q.push(a[temp.r]);
        if (!isson) {
            if (temp.l == 0 && temp.r != 0) NO = 1;
            if ((temp.l != 0 && temp.r == 0)||(temp.l==0&&temp.r==0)) isson = 1;
        } else {
            if (temp.l || temp.r) NO = 1;
        }
    }
    printf("\n");
}

int main() {
    int n;
    cin >> n;
    int x;
    cin >> x;
    root = 1;
    New(x);
    for (int i = 1; i < n; i++) {
        cin >> x;
        insert(root, x);
    }
    bfs();
    if (NO) cout << "NO" << endl;
    else cout << "YES" << endl;
    return 0;
}
View Code1(太长不看版)
#include "bits/stdc++.h"

using namespace std;
int a[100];
int n;

void build(int x) {
    int p = 1;
    while (true) {
        if (a[p] == -1) {
            a[p] = x;
            return;
        }
        if (a[p] < x) {
            p *= 2;
        } else {
            p = p * 2 + 1;
        }
    }
}

void check() {
    int flag = 0;
    int cnt = 0;
    for (int i = 1; i < 100; i++) {
        if (a[i] != -1) {
            cnt++;
            cout << a[i] << (cnt == n ? "\n" : " ");
        } else {
            flag = 1;
        }
        if (cnt == n) break;
    }
    cout << (flag ? "NO" : "YES") << endl;
}

int main() {
    cin >> n;
    int x;
    memset(a, -1, sizeof(a));
    for (int i = 0; i < n; i++) {
        cin >> x;
        build(x);
    }
    check();
    return 0;
}
View Code2(简短一点的)

 

7-14 直捣黄龙 (30 分)
7-14 直捣黄龙 (30 分)
本题是一部战争大片 —— 你需要从己方大本营出发,一路攻城略地杀到敌方大本营。首先时间就是生命,所以你必须选择合适的路径,以最快的速度占领敌方大本营。当这样的路径不唯一时,要求选择可以沿途解放最多城镇的路径。若这样的路径也不唯一,则选择可以有效杀伤最多敌军的路径。

输入格式:
输入第一行给出2个正整数N(2 ≤ N ≤ 200,城镇总数)和K(城镇间道路条数),以及己方大本营和敌方大本营的代号。随后N-1行,每行给出除了己方大本营外的一个城镇的代号和驻守的敌军数量,其间以空格分隔。再后面有K行,每行按格式城镇1 城镇2 距离给出两个城镇之间道路的长度。这里设每个城镇(包括双方大本营)的代号是由3个大写英文字母组成的字符串。

输出格式:
按照题目要求找到最合适的进攻路径(题目保证速度最快、解放最多、杀伤最强的路径是唯一的),并在第一行按照格式己方大本营->城镇1->...->敌方大本营输出。第二行顺序输出最快进攻路径的条数、最短进攻距离、歼敌总数,其间以1个空格分隔,行首尾不得有多余空格。

输入样例:
10 12 PAT DBY
DBY 100
PTA 20
PDS 90
PMS 40
TAP 50
ATP 200
LNN 80
LAO 30
LON 70
PAT PTA 10
PAT PMS 10
PAT ATP 20
PAT LNN 10
LNN LAO 10
LAO LON 10
LON DBY 10
PMS TAP 10
TAP DBY 10
DBY PDS 10
PDS PTA 10
DBY ATP 10
输出样例:
PAT->PTA->PDS->DBY
3 30 210
7-14 直捣黄龙 (30 分)
 就是一个最短路,我用的Dijkstra。一开始是建的一个包含字符串的结构体来用map做城市的结点映射,不知道为什么会不对,已经插入到map里的key值却查询不到。后来直接用string做key值。比赛时写的太慌乱,数组大小就开了100,导致有一个点没有过
#include "bits/stdc++.h"

using namespace std;
const int maxn = 300;
int pre[maxn];

int n, k;
int num[maxn];
int dist[maxn], town[maxn], kil[maxn];
int dd[maxn][maxn];
int road[maxn];
map<string, int> mp;
map<int, string> pm;
int tot = 0;
int s, d, vis[maxn];
string st1, st2;

void djs() {
    memset(dist, 0x3f, sizeof(dist));
    dist[s] = 0;
    road[s] = 1;
    for (int i = 1; i < tot; i++) {
        int x = 0;
        int flag = 0;
        for (int j = 1; j <= tot; j++) {
            if (!vis[j] && (flag == 0 || dist[j] < dist[x])) {
                flag = 1;
                x = j;
            }
        }
        vis[x] = 1;
        for (int j = 1; j <= tot; j++) {
            if (dist[x] + dd[x][j] < dist[j]) {
                dist[j] = dist[x] + dd[x][j];
                town[j] = town[x] + 1;
                kil[j] = kil[x] + num[j];
                pre[j] = x;
                road[j] = road[x];
            } else if (dist[x] + dd[x][j] == dist[j]) {
                road[j] += road[x];
                if (town[x] + 1 > town[j]) {
                    town[j] = town[x] + 1;
                    pre[j] = x;
                    kil[j] = kil[x] + num[j];

                } else if (town[x] + 1 == town[j] && kil[x] + num[j] > kil[j]) {
                    town[j] = town[x] + 1;
                    pre[j] = x;
                    kil[j] = kil[x] + num[j];
                }
            }
        }
    }

}


int id(string st) {
    if (mp.count(st)) {
        return mp[st];
    }
    mp[st] = ++tot;
    pm[tot] = st;
    return tot;
}

int main() {
    cin >> n >> k;
    cin >> st1;
    s = id(st1);
    cin >> st1;
    d = id(st1);
    int x;
    for (int i = 0; i < n - 1; i++) {
        cin >> st1 >> x;
        num[id(st1)] = x;
    }
    int a, b;
    memset(dd, 0x3f, sizeof(dd));
    for (int i = 0; i < k; i++) {
        cin >> st1 >> st2 >> x;
        a = id(st1);
        b = id(st2);
        dd[a][b] = x;
        dd[b][a] = x;
    }
    djs();
    x = d;
    vector<int> roads;
    roads.push_back(d);
    while (x != s) {
        roads.push_back(pre[x]);
        x = pre[x];
    }
    int flag = 0;
    for (int i = roads.size() - 1; i >= 0; i--) {
        if (flag) printf("->");
        flag = 1;
        cout << pm[roads[i]];
    }
    printf("\n");
    cout << road[d] << " " << dist[d] << " " << kil[d] << endl;
    return 0;
}
View Code

 

7-15 水果忍者 (30 分)

2010年风靡全球的“水果忍者”游戏,想必大家肯定都玩过吧?(没玩过也没关系啦~)在游戏当中,画面里会随机地弹射出一系列的水果与炸弹,玩家尽可能砍掉所有的水果而避免砍中炸弹,就可以完成游戏规定的任务。如果玩家可以一刀砍下画面当中一连串的水果,则会有额外的奖励,如图1所示。

中国石油大学天梯赛真题模拟第二场_第1张图片

图 1

现在假如你是“水果忍者”游戏的玩家,你要做的一件事情就是,将画面当中的水果一刀砍下。这个问题看上去有些复杂,让我们把问题简化一些。我们将游戏世界想象成一个二维的平面。游戏当中的每个水果被简化成一条一条的垂直于水平线的竖直线段。而一刀砍下我们也仅考虑成能否找到一条直线,使之可以穿过所有代表水果的线段。

中国石油大学天梯赛真题模拟第二场_第2张图片

图 2

如图2所示,其中绿色的垂直线段表示的就是一个一个的水果;灰色的虚线即表示穿过所有线段的某一条直线。可以从上图当中看出,对于这样一组线段的排列,我们是可以找到一刀切开所有水果的方案的。

另外,我们约定,如果某条直线恰好穿过了线段的端点也表示它砍中了这个线段所表示的水果。假如你是这样一个功能的开发者,你要如何来找到一条穿过它们的直线呢?

输入格式:

输入在第一行给出一个正整数N104​​),表示水果的个数。随后N行,每行给出三个整数x、y1​​、y2​​,其间以空格分隔,表示一条端点为(x,y1​​)和(x,y2​​)的水果,其中y1​​>y2​​。注意:给出的水果输入集合一定存在一条可以将其全部穿过的直线,不需考虑不存在的情况。坐标为区间 [106​​,106​​) 内的整数。

输出格式:

在一行中输出穿过所有线段的直线上具有整数坐标的任意两点p1​​(x1​​,y1​​)和p2​​(x2​​,y2​​),格式为 x1​​y1​​x2​​y2​​。注意:本题答案不唯一,由特殊裁判程序判定,但一定存在四个坐标全是整数的解。

输入样例:

5
-30 -52 -84
38 22 -49
-99 -22 -99
48 59 -18
-36 -50 -72

输出样例:

-99 -99 -30 -52


对于所有线段的上端点求一个下凸,下端点求一个上凸,因为题目说一定存在一个可行解,则可行解一定在这两个凸包之间。分为两种情况
一、对于上端点的下凸中,存在一条边使所有的下端点都在它的下面,那么这条边就是一个可行解。


二、否则就在下端点中找一条边使所有的上端点都在这条边的上面。


 
          
#include "bits/stdc++.h"

using namespace std;
const int maxn = 1e4 + 1000;
const int inf = 0x3f3f3f3f;
int sup[maxn], sdown[maxn];
int n;
struct point {
    int x, y;
} up[maxn], down[maxn];

bool cmp(point a, point b) {
    if (a.x != b.x) return a.x < b.x;
    return a.y < b.y;
}


bool checkup(point a, point b, point c) {//不满足下凸返回true
    return 1ll * (b.x - a.x) * (c.y - b.y) - 1ll * (c.x - b.x) * (b.y - a.y) < 0;
}

bool checkdown(point a, point b, point c) {//不满足上凸返回true
    return 1ll * (b.x - a.x) * (c.y - b.y) - 1ll * (c.x - b.x) * (b.y - a.y) > 0;
}

int main() {
    cin >> n;
    int a, b, c;
    for (int i = 0; i < n; i++) {
        cin >> a >> b >> c;
        up[i].x = down[i].x = a;
        up[i].y = b;
        down[i].y = c;
    }

    sort(up, up + n, cmp);
    sort(down, down + n, cmp);
    int dx = 0;
    int to = n;
    for (int i = 1; i < n; i++) {
        if (up[i].x == up[dx].x) {
            up[i].x = inf;
            up[dx].y = min(up[i].y, up[dx].y);
            to--;
        } else {
            dx = i;
        }
    }
    dx = 0;
    for (int i = 1; i < n; i++) {
        if (down[i].x == down[dx].x) {
            down[i].x = inf;
            down[dx].y = max(down[i].y, down[dx].y);
        } else {
            dx = i;
        }
    }
    sort(up, up + n, cmp);
    sort(down, down + n, cmp);
    if (to == 1) {
        printf("%d %d %d %d\n", up[0].x, up[0].y, down[0].x, down[0].y);
        return 0;
    }
    int upos = 0, dpos = 0;
    for (int i = 0; i < to; i++) {
        while (upos >= 2 && checkup(up[sup[upos - 2]], up[sup[upos - 1]], up[i]))
            upos--;
        sup[upos++] = i;
        while (dpos >= 2 && checkdown(down[sdown[dpos - 2]], down[sdown[dpos - 1]], down[i]))
            dpos--;
        sdown[dpos++] = i;
    }
    int i, j;
    point ansl, ansr;
    for (i = 0; i < upos - 1; i++) {
        for (j = 0; j < dpos; j++) {
            if (checkup(up[sup[i]], down[sdown[j]], up[sup[i + 1]])) break;
        }
        if (j == dpos) break;
    }

    if (i == upos - 1) {
        for (i = 0; i < dpos - 1; i++) {
            for (j = 0; j < upos; j++) {
                if (checkdown(down[sdown[i]], up[sup[j]], down[sdown[i + 1]])) break;
            }
            if (j == upos) break;
        }
        ansl = down[sdown[i]];
        ansr = down[sdown[i + 1]];
    } else {
        ansl = up[sup[i]];
        ansr = up[sup[i + 1]];
    }
    printf("%d %d %d %d\n", ansl.x, ansl.y, ansr.x, ansr.y);
    return 0;
}
View Code

 

posted @ 2019-03-13 17:23 Albert_liu 阅读( ...) 评论( ...) 编辑 收藏

你可能感兴趣的:(中国石油大学天梯赛真题模拟第二场)