HDU - 7303 Chaos Begin( 2023“钉耙编程”中国大学生算法设计超级联赛第三场 D)

4 篇文章 0 订阅

题目

Long long ago, there were n points a 1 , a 2 , … , a n a_1,a_2,…,a_n a1,a2,,an on the 2D plane. The world keeps stable for a long time. However, it begins to be chaotic recently when another n points b 1 , b 2 , … , b n b_1,b_2,…,b_n b1,b2,,bn appeared, where b i = a i + ( Δ x , Δ y ) b_i=a_i+(Δx,Δy) bi=ai+(Δx,Δy). And now, these 2 n 2n 2n points have already lost their identifiers.

You are given these 2 n 2n 2n points in an arbitrary order, you need to figure out all the possible ( Δ x , Δ y ) (Δx,Δy) (Δx,Δy) to help the world recover from chaos.

题目大意

很久很久以前,在二维平面上有 n n n 个点 a 1 , a 2 , … , a n a_1,a_2,\dots,a_n a1,a2,,an。世界在很长一段时间内保持稳定。

然而,最近又出现了 n n n 个点 b 1 , b 2 , … , b n b_1, b_2,\dots,b_n b1,b2,,bn,其中 b i = a i + ( Δ x , Δ y ) bi=ai+(Δx,Δy) bi=ai+(Δx,Δy)。现在,这 2 n 2n 2n 个点已经失去了它们的标识符。

2 n 2n 2n 个点以任意顺序给定,你需要找出所有可能的 ( Δ x , Δ y ) (Δx,Δy) (Δx,Δy) 来帮助世界从混乱中恢复过来。

思路

题目中给出了数据是随机的,这启发了我们暴力优化的做法。

我们首先先将所有的点按 x x x 的大小排序(相等就按 y y y 的大小排序)。

我们可以固定一个点(最好是 x x x 最小的点),然后枚举这个点的匹配点,此时我们就能求出所有可能 ( Δ x , Δ y ) (Δx,Δy) (Δx,Δy),然后我们来看看如何判断 ( Δ x , Δ y ) (Δx,Δy) (Δx,Δy) 是否满足条件。

我们对于每一个点,都看一下当前点加上 ( Δ x , Δ y ) (Δx,Δy) (Δx,Δy) 后有没有对应的点,可以用 map \text{map} map 来维护,如果找不到对应的点则说明这个 ( Δ x , Δ y ) (Δx,Δy) (Δx,Δy) 是不合法的。

于是乎我们就能找出所有满足条件的 ( Δ x , Δ y ) (Δx,Δy) (Δx,Δy)

要注意的点就是他给出的数据有重点(为啥随机数据都能有重点???),在 map \text{map} map 里面还要用 vector \text{vector} vector 记录当前位置所有的点,然后对于 ( Δ x , Δ y ) (Δx,Δy) (Δx,Δy) 也要判重。

关于时间复杂度,我只能说这个思路的时间复杂度是 O ( O( O(能过 ) ) ),至少我的代码在 hdu \text{hdu} hdu 的数据下比 hdu \text{hdu} hdu 官方给出的做法跑的快。

代码

#include <bits/stdc++.h>
using namespace std;
int T, n, m, cnt, bz[1000005];
struct node {
    int x, y;
    friend bool operator< (node a, node b) { return a.x < b.x || (a.x == b.x && a.y < b.y); }
} a[1000005], p, ans[1000005];
map <node, vector <int> > mp;
map <node, int> mpa;
int main() {
    scanf("%d", &T);
    while (T--) {
        scanf("%d", &n), cnt = 0, mp.clear(), mpa.clear();
        for (int i = 1; i <= 2 * n; i++)
            scanf("%d%d", &a[i].x, &a[i].y);
        sort(a + 1, a + 2 * n + 1);
        for (int i = 1; i <= 2 * n; i++)
            mp[a[i]].push_back(i);
        for (int i = 2; i <= 2 * n; i++) {
            bz[1] = bz[i] = 1, m = n - 1;
            int j = 2, x = a[i].x - a[1].x, y = a[i].y - a[1].y;
            for (; j <= 2 * n; j++)
                if (!bz[j]) {
                    p.x = a[j].x + x, p.y = a[j].y + y;
                    if (!mp[p].size())
                        break;
                    int k = -1;
                    for (int i = 0; i < mp[p].size(); i++)
                        if (!bz[mp[p][i]] && mp[p][i] != j) {
                            k = i;
                            break;
                        }
                    if (~k)
                        bz[mp[p][k]] = 1, bz[j] = 1, m--;
                    else
                        break;
                }
            if (!m) {
                if (x == 0 && y == 0) {
                    ans[++cnt].x = x, ans[cnt].y = y;
                    if (mpa[ans[cnt]])
                        cnt--;
                    else
                        mpa[ans[cnt]] = 1;
                }
                else {
                    ans[++cnt].x = x, ans[cnt].y = y;
                    ans[++cnt].x = -x, ans[cnt].y = -y;
                    if (mpa[ans[cnt]])
                        cnt -= 2;
                    else
                        mpa[ans[cnt]] = mpa[ans[cnt - 1]] = 1;
                }
            }
            for (int l = 1; l < j; l++) {
                p.x = a[j].x + x, p.y = a[j].y + y;
                bz[l] = 0;
                for (int i = 0; i < mp[p].size(); i++)
                    bz[mp[p][i]] = 0;
            }
            bz[i] = 0;
        }
        sort(ans + 1, ans + 1 + cnt);
        printf("%d\n", cnt);
        for (int i = 1; i <= cnt; i++)
            printf("%d %d\n", ans[i].x, ans[i].y);
    }
    return 0;
}
  • 6
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值