ACM模版

描述

题解

一开始我想着用模拟做,通过 B 状态推出前一个 A 状态,然后验证一下是否可以通过 A 状态推出 B’ 状态,使得 B’ = B,不断往前推,直到无法通过验证结束,但是不知哪里写残了还是啥,WA 了一片片,如果是 TLE 的话,正是我预料之中的,但是 WA 是我意料之外的结果……找了半天没有找到 bug 所在,坑死了……

然后发现可以通过枚举点之间的状态来缩小结果,比如:

20300

结果为 1,而如果把第三行数据换成 2 0,那么结果就是 0,根据这个推算,当两点同行或者同列并且两点之间无其他点,那么结果可以缩小为两点之间距离之差 - 2,经过任意两点缩小可以获得一个比较优的值,但是这不一定是最优的,因为我们还可能存在不是同行或者同列的点也可以缩小结果,这个就稍微复杂了,我们需要引入第三点进行三点之间关系的进一步判断。

这里就不做详细说明了,关于三点之间关系判定的代码写得比较清楚,请仔细考究代码吧~~~

这里我发现有一个问题无法理解,按照题意,应该只要有两点之间的横坐标或者纵坐标的距离大于等于 2 就一定是有限回合操作,可是测试数据却告诉我说他等于 -1 ……纳闷儿了……

代码

//
// main.cpp
// f-51Nod-1345-画点集
//
// Created by ZYJ on 2017/5/17.
// Copyright ? 2017年 ZYJ. All rights reserved.
//

#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int MAXN = 55;
const int MAX_MAP = 77;
const int INF = 0x3f3f3f3f;

pair<int, int> node[MAXN];
int map[MAX_MAP * 2][MAX_MAP * 2];

// 判断两点之间是否有点
bool check(pair<int, int> &s, pair<int, int> &e, bool tag)
{
    if (s.second == e.second)
    {
        int st = min(s.first, e.first) + 1;
        int ed = max(s.first, e.first);
        if (!tag)
        {
            ed -= 1;
        }
        if (st > ed)
        {
            return false;
        }
        for (int i = st; i <= ed; i++)
        {
            if (!map[i][s.second])
            {
                return false;
            }
        }
    }
    else
    {
        int st = min(s.second, e.second) + 1;
        int ed = max(s.second, e.second);
        if (!tag)
        {
            ed -= 1;
        }
        if (st > ed)
        {
            return false;
        }
        for (int i = st; i <= ed; i++)
        {
            if (!map[s.first][i])
            {
                return false;
            }
        }
    }
    return true;
}

int solve(int n)
{
    int res = INF;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0 ; j < n;j++)
        {
            if (i == j)
            {
                continue;
            }
            int flag = 0;
            if (node[i].first == node[j].first)
            {
                int tmp = abs(node[i].second - node[j].second) - 2;
                if (tmp >= 0)   // 当两点横坐标大于等于2时
                {
                    if (!check(node[i], node[j], false))
                    {
                        res = min(res, tmp);
                    }
                }
            }
            else if (node[i].second == node[j].second)
            {
                int tmp = abs(node[i].first - node[j].first) - 2;
                if (tmp >= 0)   // 当两点纵坐标大于等于2时
                {
                    if (!check(node[i], node[j], false))
                    {
                        res = min(res, tmp);
                    }
                }
            }
            else
            {
                // flag(B) 00/01/10/11 j 在 i 右上/右下/左上/左下
                if (node[j].first > node[i].first)
                {
                    flag |= 1;
                }
                if (node[j].second < node[i].second)
                {
                    flag |= 2;
                }
                for (int k = 0; k < n; k++) // 枚举三点关系
                {
                    if (k == i || k == j)
                    {
                        continue;
                    }
                    int flag_ = 0;
                    // flag_(B) 00/01/10/11 k 在 i 右上/右下/左上/左下
                    if (node[k].first > node[i].first)
                    {
                        flag_ |= 1;
                    }
                    else if (node[k].first == node[i].first)
                    {
                        continue;
                    }
                    if (node[k].second < node[i].second)
                    {
                        flag_ |= 2;
                    }
                    else if (node[k].second == node[i].second)
                    {
                        continue;
                    }
                    // j 和 k 在同一象限或者分别在一(二)和三(四)象限
                    if (flag == flag_ || (flag ^ flag_) == 3)
                    {
                        continue;
                    }
                    // j 和 k 在 i 的一侧
                    if ((flag & 1) == (flag_ & 1))  // down or up
                    {
                        int tmp = -1;
                        tmp = abs(node[i].first - node[j].first) - 2;
                        tmp = max(abs(node[i].first - node[k].first) - 2, tmp);
                        tmp = max(abs(node[k].second - node[j].second) - 2, tmp);
                        pair<int, int> s = abs(node[i].first - node[j].first) > abs(node[i].first - node[k].first) ? node[j] : node[k];
                        s.first = node[i].first;
                        if (!check(node[i], s, true))
                        {
                            res = min(tmp, res);
                        }
                    }
                    else                            // left or right
                    {
                        int tmp = -1;
                        tmp = abs(node[i].second - node[j].second) - 2;
                        tmp = max(abs(node[i].second - node[k].second) - 2, tmp);
                        tmp = max(abs(node[k].first - node[j].first) - 2, tmp);
                        pair<int, int> s = abs(node[i].second - node[j].second) > abs(node[i].second - node[k].second) ? node[j] : node[k];
                        s.second = node[i].second;
                        if (!check(node[i], s, true))
                        {
                            res = min(tmp, res);
                        }
                    }
                }
            }
        }
    }
    if (res == INF)
    {
        res = -1;
    }
    return res;
}

int main()
{
    //freopen("/Users/zyj/Desktop/input.txt", "r", stdin);

    int T;
    scanf("%d", &T);

    int n;
    for (int i = 0; i < T;i++)
    {
        memset(map, 0, sizeof(map));

        scanf("%d", &n);
        for (int j = 0; j < n; j++)
        {
            scanf("%d%d", &node[j].first, &node[j].second);
            node[j].first += MAX_MAP;
            node[j].second += MAX_MAP;
            map[node[j].first][node[j].second] = 1;
        }

        printf("%d\n", solve(n));
    }

    return 0;
}