题目描述
农民约翰周末进行高能物理实验的兴趣已经回升,导致N个虫洞(2 <= N <= 12,N均匀)实现在他的农场,每个位于他农场二维图上的一个不同点x,y坐标都是整数)。
例如,假设在(1,1)和B(3,1)处有两个成对的虫洞A,而Bessie牛从从+ x方向移动的位置(2,1)开始。 Bessie将进入虫洞B [at(3,1)],退出A [at(1,1)],然后再次输入B,等等,被困在无限循环中!
| 。 。 。 。
| A> B。 Bessie将前往B
+。 。 。 。然后再一次到B
农夫约翰知道他农场上每个虫洞的确切位置。他知道Bessie牛总是走在+ x方向,尽管他不记得Bessie目前所在的地方。
请帮助农民约翰计数不同配对的虫洞数量,如果她从不幸的位置开始,Bessie可能会陷入无限循环。 FJ不知道哪个虫洞对与任何其他虫洞,所以找到所有的可能性(即,所有的不同的方式,N虫洞可以配对,以便贝西可以在某种程度上进入一个循环)。请注意,具有较少数量的虫洞的环路可能会对总计数产生许多不同的配对集合,因为那些不在环路中的虫洞以许多不同的方式配对。
程序名称:wormhole
根据他的计算,农夫约翰知道他的虫洞将形成N / 2连接对。例如,如果将A洞和B洞作为一对连接,那么进入虫洞A的任何物体都将退出沿相同方向移动的虫孔B,进入虫孔B的任何物体也将同样从同一方向移动的虫洞A退出。这可能会产生不愉快的后果。
输入格式
第1行:虫洞数目N.
第2..1 + N行:每行包含描述单个虫洞的(x,y)坐标的两个空格分隔的整数。 每个坐标在百万分之100,000,000
输入 (file wormhole.in)
4 0 0 1 0 1 1 0 1
输入注释:
有四个虫洞,形成一个广场的角落。
输出格式
第1行:不同配对的虫洞的数量,使得Bessie可以从+ x方向的某个起始点走出一个循环。
输出(file wormhole.out)
2
输出注释:
这如果我们从输入中读出蠕虫洞1..4,那么如果虫洞1与虫洞2和虫洞3对配有虫洞4,Bessie可以在(0,0)和(1 ,0)或(0,1)和(1,1)之间。
|。。。。
4 3。。。 Bessie将前往B
1-2-.-.-。 然后再一次到B
同样地,如果配对是1-3和2-4(如果Bessie进入WH#3,并出现在WH#1,她然后走到WH#2,运输) 这里是WH#4,再次引导她进入WH#3循环)。
只有配对1-4和2-3允许Bessie从2D平面上的任何一点在+ x方向行走,没有骑自行车的危险。
解题代码
/*
ID:15189822
PROG:wormhole
LANG:C++
*/
//官方解答
#include <iostream>
#include <fstream>
using namespace std;
#define MAX_N 12
int N, X[MAX_N+1], Y[MAX_N+1];
int partner[MAX_N+1];
int next_on_right[MAX_N+1];
ifstream fin("wormhole.in");
ofstream fout("wormhole.out");
bool cycle_exists(void){
for (int start=1; start<=N; start++){
// does there exist a cylce starting from start
int pos = start;
for (int count=0; count<N; count++){
pos = next_on_right[partner[pos]];
}
if (pos != 0) return true;
}
return false;
}
// count all solutions
int solve(void){
// find first unpaired wormhole
int i, total=0;
for (i=1; i<=N; i++)
if (partner[i] == 0) break;
// everyone paired?
if (i > N) {
if (cycle_exists()) return 1;
else return 0;
}
// try pairing i with all possible other wormholes j
for (int j=i+1; j<=N; j++)
if (partner[j] == 0) {
// try pairing i & j, let recursion continue to
// generate the rest of the solution
partner[i] = j;
partner[j] = i;
total += solve();
partner[i] = partner[j] = 0;
}
return total;
}
int main(){
fin >> N;
for (int i=1; i<=N; i++) fin >> X[i] >> Y[i];
fin.close();
for (int i=1; i<=N; i++) // set next_on_right[i]...
for (int j=1; j<=N; j++)
if (X[j] > X[i] && Y[i] == Y[j]) // j right of i...
if (next_on_right[i] == 0 ||
X[j]-X[i] < X[next_on_right[i]]-X[i])
next_on_right[i] = j;
//找出紧邻的右边平行点
fout << solve() << "\n";
// cout<<solve()<<endl;
fout.close();
return 0;
}