每天农夫约翰都会去巡视农场,检查他的 连接奶牛(春季每日一题 56)_#define

每头奶牛的位置由二维平面中的一个点描述,而约翰从原点 连接奶牛(春季每日一题 56)_全排列_02

所有奶牛的位置互不相同,且都不在原点。

为了使自己的路线更有趣,农夫约翰决定只沿平行于坐标轴的方向行走,即只能向北,向南,向东或向西行走。

此外,他只有在到达奶牛的位置时才能改变行进方向(如果需要,他也可以选择通过奶牛的位置而不改变方向)。

在他改变方向时,可以选择转向 连接奶牛(春季每日一题 56)_ios_03连接奶牛(春季每日一题 56)_dfs_04

约翰的行进路线必须满足在他访问完所有奶牛后能够回到原点。

如果他在每头奶牛的位置处恰好转向一次,请计算出约翰访问他的 连接奶牛(春季每日一题 56)_#define

允许他在不改变方向的情况下通过任意奶牛的位置任意次数。

同一几何路线正向走和反向走算作两条不同的路线。

输入格式
第一行包含整数 连接奶牛(春季每日一题 56)_#define

接下来 连接奶牛(春季每日一题 56)_#define 行,每行包含两个整数 连接奶牛(春季每日一题 56)_i++_08

输出格式
输出不同路线的数量。

如果不存在有效路线,则输出 连接奶牛(春季每日一题 56)_#define_09

数据范围
连接奶牛(春季每日一题 56)_i++_10,
连接奶牛(春季每日一题 56)_dfs_11

输入样例:

4
0 1
2 1
2 0
2 -5

输出样例:

2

样例解释
共有两条不同路线 连接奶牛(春季每日一题 56)_i++_12连接奶牛(春季每日一题 56)_i++_13


连接奶牛(春季每日一题 56)_ios_14 全排列枚举顺序,然后对每种排列进行判断,当从一个到另一个点时,必须有 连接奶牛(春季每日一题 56)_#define_15 坐标 或者 连接奶牛(春季每日一题 56)_全排列_16

#include<iostream>

#define x first
#define y second

using namespace std;

const int N = 15;

typedef pair<int, int> PII;

int n, res;
int a[N];
PII q[N];
bool st[N];

bool check(){
int x = 0, y = 0;
int dx, dy, rdx = -10, rdy = -10;

for(int i = 0; i <= n; i++){
int idx = a[i];
if(q[idx].x != x && q[idx].y != y) return false;

if(q[idx].x == x) dx = 0, dy = (q[idx].y - y) / abs(q[idx].y - y);
if(q[idx].y == y) dy = 0, dx = (q[idx].x - x) / abs(q[idx].x - x);

if(dx == rdx && dy == rdy) return false;

rdx = dx, rdy = dy;
x = q[idx].x, y = q[idx].y;
}

return x == 0 && y == 0;
}

void dfs(int cnt){
if(cnt == n){
if(check()) res++;
return;
}
for(int i = 0; i < n; i++){
if(st[i]) continue;
st[i] = true;
a[cnt] = i;
dfs(cnt + 1);
a[cnt] = -1;
st[i] = false;
}
}

int main(){

cin >> n;
for(int i = 0; i < n; i++)
cin >> q[i].x >> q[i].y;

q[n].x = 0, q[n].y = 0;
a[n] = n;
dfs(0);

cout << res << endl;

return 0;
}