【JSCPC】2021江苏省赛 D. Pattern Lock | 构造
题目链接
题目
题目大意
行 列的点阵图,要求构造 个整点的排列,排列中任意相邻两个点构成一条线段,满足以下条件:
- 任一线段不经过除端点外的其他整点。
- 相邻两条线段形成的角是锐角。
数据范围:。
思路
有多种解法,下面给出一种合法的构造方式:
总体思想为尽量走 Z 字,每相邻两个点的横坐标或纵坐标相差 即可保证不每个线段不经过其他点。
蓝色部分
如果 为偶数,我们可以每两行为一组进行构造。
具体实现如下:
//从第 u 行到第 d 行,第 l 列到第 r 列用蓝色方式进行覆盖
void solven(int u,int d,int l,int r)
{
for (int i=u,t=0;i<=d;i+=2,t=!t)
{
if (t&1)
{
for (int j=r;j>l;--j) ans.push_back({i,j}),ans.push_back({i+1,j-1});
ans.push_back({i,l});
ans.push_back({i+1,r});
}
else
{
for (int j=l;j<r;++j) ans.push_back({i,j}),ans.push_back({i+1,j+1});
ans.push_back({i,r});
ans.push_back({i+1,l});
}
}
}
这里有一种特殊情况,若 为偶数但不等于 ,且 时,用这种方法覆盖会出现直角,所以进行讨论时这种情况转到黄色部分的构造方法。
黄色部分
如果 为偶数,我们可以每两列为一组进行构造,具体实现与蓝色部分类似,详见代码不再赘述。同样的,若 为偶数但不等于 ,且 时,用黄色部分的构造方法会出现直角,所以在这种情况下应该使用蓝色构造方法。
红色部分
当 和 均为奇数时,我们从左上角取出一个 的矩阵直接手玩出答案,就可以把剩下的部分划分成两个有偶数边长的矩阵。
红色部分为手玩出来的固定解法,直接按图片将点依次加入答案即可。
ans.push_back({1,3});
ans.push_back({3,2});
ans.push_back({1,1});
ans.push_back({2,3});
ans.push_back({3,1});
ans.push_back({1,2});
ans.push_back({3,3});
ans.push_back({2,1});
ans.push_back({2,2});
离开红色部分可以直接用黄色部分的构造方法覆盖右侧的 的点阵,但是从红色部分直接转向蓝色部分会出现钝角,于是用绿色部分进行衔接。
绿色部分
当 和 均为奇数且 时,我们需要用蓝色的构造方法覆盖一个 的矩阵,但是从 点出发直接转为蓝色构造方法会出现钝角,于是用绿色构造方法进行衔接。
该部分也是手玩出来的……同样按图依次加入答案。
ans.push_back({4,1});
ans.push_back({4,2});
ans.push_back({5,1});
ans.push_back({4,3});
ans.push_back({5,2});
ans.push_back({5,3});
代码
#include <stdio.h>
#include <algorithm>
#include <vector>
using namespace std;
struct asdf{
int x,y;
};
vector<asdf> ans;
int n,m;
void solven(int u,int d,int l,int r)
{
for (int i=u,t=0;i<=d;i+=2,t=!t)
{
if (t&1)
{
for (int j=r;j>l;--j) ans.push_back({i,j}),ans.push_back({i+1,j-1});
ans.push_back({i,l});
ans.push_back({i+1,r});
}
else
{
for (int j=l;j<r;++j) ans.push_back({i,j}),ans.push_back({i+1,j+1});
ans.push_back({i,r});
ans.push_back({i+1,l});
}
}
}
void solvem(int u,int d,int l,int r)
{
for (int i=r,t=((r-l+1)/2)%2;i>=l;i-=2,t=!t)
{
if (t&1)
{
ans.push_back({d,i});
ans.push_back({u,i-1});
for (int j=u;j<d;++j) ans.push_back({j,i}),ans.push_back({j+1,i-1});
}
else
{
ans.push_back({u,i});
ans.push_back({d,i-1});
for (int j=d;j>u;--j) ans.push_back({j,i}),ans.push_back({j-1,i-1});
}
}
}
int main()
{
scanf("%d%d",&n,&m);
if (n%2==0&&m!=2) solven(1,n,1,m);
else if (m%2==0) solvem(1,n,1,m);
else
{
solvem(1,n,4,m);
ans.push_back({1,3});
ans.push_back({3,2});
ans.push_back({1,1});
ans.push_back({2,3});
ans.push_back({3,1});
ans.push_back({1,2});
ans.push_back({3,3});
ans.push_back({2,1});
ans.push_back({2,2});
if (n>3)
{
ans.push_back({4,1});
ans.push_back({4,2});
ans.push_back({5,1});
ans.push_back({4,3});
ans.push_back({5,2});
ans.push_back({5,3});
}
solven(6,n,1,3);
}
for (auto v:ans) printf("%d %d\n",v.x,v.y);
return 0;
}