题解 P1227 【[JSOI2008]完美的对称】

· · 题解

这道题的思考难度不大。

1.思路分析:

我们为什么要按x坐标或者y坐标排序呢?

考虑这些点的x坐标(y坐标)x_1x_2x_3,\cdots,x_n。将这n个数从小到大排序。

根据中点坐标公式:对于∀点(x_i, y_i)和点(x_j, y_j), 都有(x_i, y_i) 和 点(x_j, y_j)的中点坐标为:(\dfrac{x_i + x_j}{2}, \dfrac{y_i + y_j}{2})。

若最小的 x_1 不和最大的x_n搭配,则x_n一定会和一个比x_1大的数进行匹配,不妨设为x_i

x_1会和一个比x_n小的数进行匹配,不妨设为x_j

x_n > x_jx_i > x_1x_n + x_i > x_1 + x_j\dfrac{x_n + x_i}{2} > \dfrac{x_1 + x_j}{2} 所以两两不搭配,矛盾!

所以最小的x_1一定要和最大的x_n进行搭配,次小的数也要和次大的数进行搭配。y坐标也同理。

∴这道题要排序(本蒟蒻对y坐标排序,对x坐标排序也一样)。

2.代码实现:

我们如何判断这些保镖都关于一个点对称呢?

我们可以先提前算出最小的(x_1, y_1)和最大的(x_n, y_n)的中点坐标(tx = \dfrac{x_1 + x_n}{2}, ty = \dfrac{y_1 + y_n}{2})

然后再依次配对,如果有一组配对得出的答案和提前算好的(tx, ty)不等,则出现了矛盾。

如果程序到了最后没有出现矛盾,则成功了,根据题目要求输出(tx, ty)就行辣。

关键的Code:

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <iomanip>
using namespace std;

int n;
struct node {
    int x, y; 
} a[20200];

int cmp(node p,node q) { // 普通的结构体排序的cmp函数,当然在结构体里写重载运算符也珂以。
    if(p.y == q.y) return p.x < q.x; // 也要判断y坐标相等的情况。
    return p.y < q.y;
} 

inline int read() { //快读,没啥话好说。
    register int x = 0, f = 1;
    char ch = getchar();
    while (!isdigit(ch)) {
        if (ch == '-') f = -1;
        ch = getchar();
    }
    while (isdigit(ch)) {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
} 

void init() { // 为了使主函数看起来更简便,则把主函数中的代码放到一个单独的函数里,方便检查。
    int i, j;
    double tx, ty, px, py;
    cin >> n; 
    for(i = 1; i <= n; i++) 
        cin >> a[i].x >> a[i].y;
    sort(a + 1, a + n + 1, cmp);// 对结构体进行y坐标排序。
    tx=(a[1].x + a[n].x + (0.0))/2;
    ty=(a[1].y + a[n].y + (0.0))/2; //注意整数除以2不一定是整数,int转double要和0.0一起操作。
    for(i = 1,j = n;i <= j; i++,j--) { //类似于two-pointers.
        px = (a[i].x + a[j].x + (0.0))/2;
        py = (a[i].y + a[j].y + (0.0))/2;
        if(px != tx || py != ty) {
            printf("This is a dangerous situation!\n"); //此时已出现矛盾。
            return;
        }
    }
    cout<<"V.I.P. should stay at ("<<fixed<<setprecision(1)<<tx<<","<<fixed<<setprecision(1)<<ty<<")."<<endl; //没有出现矛盾,根据题目要求输出即可。
}

int main() {
    init();//在主函数里调用。
    return 0;
}