『题解』CF28A Bender Problem

题意

\(n\) 个钉子,从 \(1 \sim n\) 编号,有 \(m\) 条铁棒,要求用这些铁棒和钉子围成一个封闭的折线。要求铁棒不一定全部用完,铁棒必须平行于坐标轴。

现在他要把铁棒弯成直角,这样中间的折叠点一个钉子,两头各一个钉子,要求折叠的这颗钉子之前必须是没有别的棒连接的(也就是空钉子),问怎么选棒,棒只能用一次。

如果无法解决 Bender 的问题,请输出 NO 。否则,在第一行中输出 YES ,在第二行中输出 \(n\) 个数字,其中第 \(i\) 个数表示杆的数量,该折叠位置固定在第 \(i\) 个钉上;如果没有这样的杆,则输出 \(-1\)

思路

用铁棒把钉子框起来,每个铁棒只能折叠一次。

由题意我们可以得出,如果一个铁棒在第 \(i\) 个钉子处折叠,那么第 \(i+1\) 个就一定不是折叠的。

题目中钉子按顺序给出,所以我们只需要枚举每个钉子,判断是奇数或者偶数点,看是否满足即可。

注意初始条件。

CODE

/*

Name: CF28A Bender Problem

Solution: 瞎搞
   

By Frather_

*/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#define ll long long
#define InF 0x3f3f3f3f
#define kMax 10e5
#define kMin -10e5
#define kMod 998244353
using namespace std;
/*==================================================快读*/
inline int read()
{
    int X = 0, F = 1;
    char CH = getchar();
    while (CH < '0' || CH > '9')
    {
        if (CH == '-')
            F = -1;
        CH = getchar();
    }
    while (CH >= '0' && CH <= '9')
    {
        X = (X << 3) + (X << 1) + (CH ^ 48);
        CH = getchar();
    }
    return X * F;
}
/*===============================================定义变量*/
int n, m;

const int _ = 10010;

int x[_], y[_], rod[_], ans[_];
bool vis[_];
bool flag;
/*=============================================自定义函数*/
int Calc(int i, int j)
{
    int x_ = abs(x[j] - x[(j + n - 1) % n]);
    int y_ = abs(y[j] - y[(j + n - 1) % n]);
    int _x = abs(x[j] - x[(j + 1) % n]);
    int _y = abs(y[j] - y[(j + 1) % n]);
    return x_ + y_ + _x + _y;
}

void prepare()
{
    memset(ans, -1, sizeof(ans)); //判断是否折叠
    memset(vis, false, sizeof(vis));
    flag = true;
}
/*=================================================主函数*/
signed main()
{
    n = read();
    m = read();
    for (int i = 0; i < n; i++)
    {
        x[i] = read();
        y[i] = read();
    }
    for (int i = 0; i < m; i++)
        rod[i] = read();

    for (int i = 0; i < 2; i++)
    {
        prepare();

        for (int j = i; j < n; j += 2)
        {
            int dis = Calc(i, j); //当前钉子与前一个或后一个的距离

            for (int k = 0; k < m; k++)
            {
                if (!vis[k] && rod[k] == dis)
                {
                    vis[k] = true;
                    ans[j] = k + 1;
                    break;
                }
            }

            if (ans[j] == -1)
            {
                flag = false;
                break;
            }
        }
        if (flag)
            break;
    }
    if (flag)
    {
        printf("YES\n%d", ans[0]);

        for (int i = 1; i < n; i++)
            printf(" %d", ans[i]);
        puts("");
    }
    else
        printf("NO\n");
    return 0;
}
原文地址:https://www.cnblogs.com/Frather/p/14698424.html