Farmer John's hobby of conducting high-energy physics experiments on weekends has backfired, causing N wormholes (2 <= N <= 12, N even) to materialize on his farm, each located at a distinct point on the 2D map of his farm (the x,y coordinates are both integers).
According to his calculations, Farmer John knows that his wormholes will form N/2 connected pairs. For example, if wormholes A and B are connected as a pair, then any object entering wormhole A will exit wormhole B moving in the same direction, and any object entering wormhole B will similarly exit from wormhole A moving in the same direction. This can have rather unpleasant consequences.
For example, suppose there are two paired wormholes A at (1,1) and B at (3,1), and that Bessie the cow starts from position (2,1) moving in the +x direction. Bessie will enter wormhole B [at (3,1)], exit from A [at (1,1)], then enter B again, and so on, getting trapped in an infinite cycle!
| . . . . | A > B . Bessie will travel to B then + . . . . A then across to B again
Farmer John knows the exact location of each wormhole on his farm. He knows that Bessie the cow always walks in the +x direction, although he does not remember where Bessie is currently located.
Please help Farmer John count the number of distinct pairings of the wormholes such that Bessie could possibly get trapped in an infinite cycle if she starts from an unlucky position. FJ doesn't know which wormhole pairs with any other wormhole, so find all the possibilities.
PROGRAM NAME: wormhole
INPUT FORMAT:
Line 1: | The number of wormholes, N. |
Lines 2..1+N: | Each line contains two space-separated integers describing the (x,y) coordinates of a single wormhole. Each coordinate is in the range 0..1,000,000,000. |
SAMPLE INPUT (file wormhole.in):
4 0 0 1 0 1 1 0 1
INPUT DETAILS:
There are 4 wormholes, forming the corners of a square.
OUTPUT FORMAT:
Line 1: | The number of distinct pairings of wormholes such that Bessie could conceivably get stuck in a cycle walking from some starting point in the +x direction. |
SAMPLE OUTPUT (file wormhole.out):
2
OUTPUT DETAILS:
If we number the wormholes 1..4 as we read them from the input, then if wormhole 1 pairs with wormhole 2 and wormhole 3 pairs with wormhole 4, Bessie can get stuck if she starts anywhere between (0,0) and (1,0) or between (0,1) and (1,1).
| . . . . 4 3 . . . Bessie will travel to B then 1-2-.-.-. A then across to B again
Similarly, with the same starting points, Bessie can get stuck in a cycle if the pairings are 1-3 and 2-4 (if Bessie enters WH#3 and comes out at WH#1, she then walks to WH#2 which transports here to WH#4 which directs her towards WH#3 again for a cycle).
Only the pairings 1-4 and 2-3 allow Bessie to walk in the +x direction from any point in the 2D plane with no danger of cycling.
(转自[USACO])
讲一下题目大意。Farmer John(USACO的标志人物啊)特别喜欢做实验,使得农场上出现了N(N <= 12)个虫洞,现在将这N个虫洞两两配对,配对了的虫洞从其中一个进入就会从对应的一个虫洞出来。Bessie在田园中总是向x轴的正方向前进。John想知道,有多少种虫洞的配对方案可以让Bessie在田园中某一个地方出发,会陷入死循环。
很明显的搜索(数据范围小),因为(1,2)(3,4)和(3,4)(1,2)是同一种匹配,所以每一次搜索的时候就找到编号最小的一个虫洞和其他的虫洞匹配。
接下来就是判断是否会陷入死循环。还算比较好想。首先给每个虫洞预处理出一个right,表示从它出来,往右走遇到的第一个虫洞的编号,如果不存在,就记个0吧。然后用个数组记录一下类似于Tarjan的时间戳的一个东西,每次循环访问的时候记一个编号(当然设成一样的),如果下一虫洞没有访问,那么就把编号设成当前的编号,否则判断它是否和现在的编号相等,如果相等,就说明会陷入死循环。
Code
1 /* 2 ID: 3 PROG: wormhole 4 LANG: C++11 5 */ 6 /** 7 * USACO 8 * Accpeted 9 * Time:0ms 10 * Memory:4184k 11 */ 12 #include<iostream> 13 #include<cstdio> 14 #include<cctype> 15 #include<cstring> 16 #include<cstdlib> 17 #include<fstream> 18 #include<sstream> 19 #include<algorithm> 20 #include<map> 21 #include<set> 22 #include<queue> 23 #include<vector> 24 #include<stack> 25 using namespace std; 26 typedef bool boolean; 27 #define INF 0xfffffff 28 #define smin(a, b) a = min(a, b) 29 #define smax(a, b) a = max(a, b) 30 template<typename T> 31 inline void readInteger(T& u){ 32 char x; 33 int aFlag = 1; 34 while(!isdigit((x = getchar())) && x != '-'); 35 if(x == '-'){ 36 x = getchar(); 37 aFlag = -1; 38 } 39 for(u = x - '0'; isdigit((x = getchar())); u = (u << 1) + (u << 3) + x - '0'); 40 ungetc(x, stdin); 41 u *= aFlag; 42 } 43 44 typedef class Point { 45 public: 46 int x; 47 int y; 48 int id; 49 boolean operator < (Point another) const { 50 if(this->y != another.y) return this->y < another.y; 51 return this->x < another.x; 52 } 53 }Point; 54 55 int n; 56 int* onright; 57 Point* ps; 58 59 inline void init(){ 60 readInteger(n); 61 ps = new Point[(const int)(n + 1)]; 62 onright = new int[(const int)(n + 1)]; 63 for(int i = 1; i <= n; i++){ 64 readInteger(ps[i].x); 65 readInteger(ps[i].y); 66 ps[i].id = i; 67 onright[i] = 0; 68 } 69 } 70 71 int* matches; 72 boolean* seced; 73 int res; 74 75 boolean check(){ 76 int vis[(const int)(n + 1)]; 77 memset(vis, 0, sizeof(vis)); 78 vis[0] = -1; 79 for(int i = 1; i <= n; i++){ 80 if(vis[i] != 0) continue; 81 int p = i; 82 while(vis[p] == 0){ 83 vis[p] = i; 84 p = onright[p]; 85 if(seced[p]) p = matches[p]; 86 } 87 if(vis[p] == i) return true; 88 } 89 return false; 90 } 91 92 void search(int choosed){ 93 if(choosed + 2 > n){ 94 if(check()) res++; 95 return; 96 } 97 int sta; 98 for(int i = 1; i <= n; i++) 99 if(!seced[i]){ 100 sta = i; 101 break; 102 } 103 seced[sta] = true; 104 for(int i = sta + 1; i <= n; i++){ 105 if(!seced[i]){ 106 matches[sta] = i; 107 matches[i] = sta; 108 seced[i] = true; 109 search(choosed + 2); 110 seced[i] = false; 111 } 112 } 113 seced[sta] = false; 114 } 115 116 inline void solve(){ 117 matches = new int[(const int)(n + 1)]; 118 seced = new boolean[(const int)(n + 1)]; 119 memset(seced, false, sizeof(boolean) * (n + 1)); 120 sort(ps + 1, ps + n + 1); 121 for(int i = 1; i < n; i++){ 122 if(ps[i + 1].y == ps[i].y){ 123 onright[ps[i].id] = ps[i + 1].id; 124 } 125 } 126 search(0); 127 printf("%d ", res); 128 } 129 130 int main(){ 131 freopen("wormhole.in", "r", stdin); 132 freopen("wormhole.out", "w", stdout); 133 init(); 134 solve(); 135 return 0; 136 }