题目描述
Farmer John 周末进行高能物理实验的结果却适得其反,导致 nn 个虫洞出现在农场上,农场是一个二维平面,没有两个虫洞处于同一位置。
根据他的计算,FJ 知道他的虫洞两两配对,形成 n22n 对配对。例如,如果 AA 和 BB 的虫洞连接成一对,进入虫洞 AA 的任何物体将从虫洞 BB 出去,方向不变;反之亦然。
然而这可能发生相当令人不快的后果。例如,假设有两个成对的虫洞 A(1,1)A(1,1) 和 B(3,1)B(3,1),Bessie 从 (2,1)(2,1) 开始朝着 xx 正方向移动。Bessie 将进入虫洞 B(3,1)B(3,1),从 A(1,1)A(1,1) 出去,然后再次进入 BB,困在一个无限循环中!
FJ 知道他的农场里每个虫洞的确切位置。他知道 Bessie 总是向 xx 正方向走进来,虽然他不记得贝茜的当前位置。
请帮助 FJ 计算有多少种虫洞配对方案,使得存在一个位置,使得 Bessie 从该位置出发,会被困在一个无限循环中。
输入格式
第一行一个正整数 nn,表示虫洞数量。
接下来 nn 行,每行两个整数 x,yx,y,表示一个虫洞的坐标。
输出格式
输出一行一个整数表示答案。
输入输出样例
输入 #1
4 0 0 1 0 1 1 0 1
输出 #1
2
说明/提示
数据范围
对于 100%100% 的数据,2≤n≤122≤n≤12,0≤x,y≤1090≤x,y≤109。
保证 nn 为偶数。
样例解释
将虫洞编号为 1∼41∼4,然后通过将 1,21,2 和 3,43,4 匹配,如果 Bessie 从 (0,0)(0,0) 到 (1,0)(1,0) 之间的任意位置出发,她会陷入无限循环中。
相似的,在相同的起始点,如果配对是 1,31,3 和 2,42,4,贝茜也会陷入循环。(如果贝西从 33 进去,11 出来,她会走向 22 ,然后被传送到 44,最后又回到 33)
仅有 1,41,4 和 2,32,3 的配对允许贝茜从任何二维平面上的点向 xx 正方向走,而不出现无限循环。
题面翻译摘自 NOCOW
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n;
struct node
{
int x;int y;
} a[30];
int b[30];
int ans;
bool cmp(node aa,node bb) //排序
{
if (aa.y==bb.y) return aa.x<bb.x;
return aa.y<bb.y;
}
int f(int num,int d,int begin,int p1) //检查,num只是用来标记的
{ //begin,记录开始位置,用来判断是否回到原点了,
//p1=1:走的方式到达点d 的,p1=0:从某虫洞到达d 的
if (num!=1&&d==begin&&p1==1) return 1; // 回到原点了,而且是用走的方式
if (p1==0) //从虫洞d出来,就往前走,如果前面有虫洞,就走过去,没有就返回0
{
if (a[d].y==a[d+1].y) return f(num+1,d+1,begin,1);
else return 0; //没有形成环就返回0
}
if (p1==1) return f(num+1,b[d],begin,0); //走到虫洞口了就跳进去
}
bool check()
{
for (int j=1;j<=n;j++) //尝试从每个点出发,看会不会形成环
if (f(1,j,j,1)==1) return 1; //有一个会形成环就返回1
return 0;
}
void dfs(int x) //配对
{
if (x==n+1) {if (check()==1) ans++;return;} //n个点都匹配完了,就检查
if (b[x]==0) //如果x没有匹配
{
for (int i=x+1;i<=n;i++) //一个点一个点的匹配
if (b[i]==0)
{
b[i]=x;b[x]=i; //标记,i匹配x,x匹配i
dfs(x+1); //往后搜
b[i]=0;b[x]=0; //还原
}
}
if (b[x]!=0) dfs(x+1); //x匹配过了就继续往后搜
return;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d%d",&a[i].x,&a[i].y);
}
sort(a+1,a+n+1,cmp); //排序按照纵坐标排,纵坐标相同按横坐标
dfs(1); //一个点一个点的匹配
printf("%d\n",ans);
return 0;
}