题目描述
Farmer John 周末进行高能物理实验的结果却适得其反,导致 nn 个虫洞出现在农场上,农场是一个二维平面,没有两个虫洞处于同一位置。
根据他的计算,FJ 知道他的虫洞两两配对,形成 n 2 \dfrac{n}{2} 2n 对配对。例如,如果 AA 和 BB 的虫洞连接成一对,进入虫洞 AA 的任何物体将从虫洞 BB 出去,方向不变;反之亦然。
然而这可能发生相当令人不快的后果。例如,假设有两个成对的虫洞 A(1,1) 和 B(3,1),Bessie 从 (2,1) 开始朝着 x 正方向移动。Bessie 将进入虫洞 B(3,1),从A(1,2) 出去,然后再次进入 B,困在一个无限循环中!
FJ 知道他的农场里每个虫洞的确切位置。他知道 Bessie 总是向 x 正方向走进来,虽然他不记得贝茜的当前位置。
请帮助 FJ 计算有多少种虫洞配对方案,使得存在一个位置,使得 Bessie 从该位置出发,会被困在一个无限循环中。
- 输入格式
第一行一个正整数 n,表示虫洞数量。
接下来 n 行,每行两个整数 x,y,表示一个虫洞的坐标。
- 输出格式
输出一行一个整数表示答案。
思路:
- 先暴搜出所有的可能答案
- 之后跑基环树的dfs来判环
int cur[N]//当前调用栈
int vis[N]//当前点是否被访问过
AC
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 20;
int n;
struct Point{
int x, y;
bool operator<(const Point& a)const {
if(y != a.y)return y < a.y;
return x < a.x;
}
} p[N];
int e[N][2];
int ans = 0;
bool st[N];
bool used[N][2], cur[N][2];
bool dfs(int a, int x){
if(cur[a][x]) return true;
if(used[a][x]) return false;
used[a][x] = cur[a][x] = 1;
bool res = false;
if(e[a][x^1] != -1)res = dfs(e[a][x^1],x^1);
cur[a][x] = 0;
return res;
}
bool check(){
memset(used, 0, sizeof used);
memset(cur, 0, sizeof cur);
for(int i = 0; i < n; i ++ )for(int j = 0; j < 2; j ++ ){
if(!used[i][j]){
if(dfs(i,j))return true;
}
}
return false;
}
void dfs(int x){
if(x >= n/2){
if(check())ans++;
return ;
}
for(int i = 0; i < n; i ++ ){
if(!st[i]){
for(int j = 0; j < n; j ++ ){
if(j == i || st[j]) continue;
st[i] = st[j] = true;
e[j][0] = i; e[i][0] = j;
dfs(x+1);
st[i] = st[j] = false;
e[j][0] = -1; e[i][0] = -1;
}
break;
}
}
}
int main(){
ios::sync_with_stdio(0);
cin>>n;
for(int i = 0; i < n; i ++ )cin>>p[i].x>>p[i].y;
sort(p,p+n);
for(int i = 0; i < n; i ++ )e[i][0] = e[i][1] = -1;
for(int i = 1; i < n; i ++ )if(p[i].y == p[i-1].y)e[i-1][1] = i;
dfs(0);
cout<<ans<<endl;
return 0;
}