USCAO-Section 1.3 Wormholes

来源:互联网 发布:c语言游戏程序代码 编辑:程序博客网 时间:2024/06/04 01:05

原题:
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 (i.e., all the different ways that N wormholes could be paired such that Bessie can, in some way, get in a cycle). Note that a loop with a smaller number of wormholes might contribute a number of different sets of pairings to the total count as those wormholes that are not in the loop are paired in many different ways.

题意:
有N个虫洞,坐标给定(本体使用的是常规的XY直角坐标系),N为偶数,现在有一个人只会向右走,起点不确定,虫洞进行两两配对,其作用是走入一个虫洞会传送到配对的虫洞处并且继续向右走。试求会使这个人从某处出发会进入一个死循环永远走不出去的配对方法数。

题解:
1、假设这个人的起点是每一个虫洞,然后模拟他从每一个虫洞出发的结果。
2、因为只能往右边走,所以只要这个人的右边没有虫洞,就不会陷入循环,这个作为我们判定他是否会进入死循环的判断条件。
3、根据上面的需求,我们需要对虫洞的坐标进行分析,找出在同一x方向上即y值相同的虫洞,并标记其右边的虫洞编号。
4、递归(DFS)求出所有的配对方法并判断是否满足题意。
所有我们需要有一个判断是否会造成死循环的判断函数;
一个进行配对方案列举的DFS递归函数
和一个计数器ans;

代码如下:

/*ID:newyear111PROG: wormholeLANG: C++*/#include <iostream>#include <fstream>#include <string>#include<algorithm>using namespace std;const int N=15;//记录虫洞坐标,虫洞的编号从1开始 struct point{    int x,y;}p[N];//right_next[i]记录编号为i的虫洞的右边的虫洞的编号,没有就为0//pairs[i]记录编号为i的虫洞的匹配的虫洞的编号是多少,未匹配就为0, int right_next[N],pairs[N];int n;//书写对坐标排序的cmp函数,以y为第一标准,y相同的以x为标准,这样处理后点会以由下向上,由左到右排列,便于进行处理 bool cmp(point a,point b){    return (a.y<b.y)||(a.y==b.y&&a.x<b.x);}//判断从编号为1-n的虫洞出发,是否会进入死循环 bool isOK(){    for(int i=1;i<=n;i++){        int t=i;        //n个虫洞最多进行n次移动(一次移动看做一个虫洞到另一个)         for(int j=0;j<n;j++){            t=right_next[pairs[t]]; //移动到下一个虫洞的右边,如果右边没有虫洞了,那么t为0         }           if(t) return true;//如果t不为0,那么久说明可以在n个虫洞移动超过n次,必然陷入了循环     }    return false;}//递归进行配对,并求出合法的配对方法数作为返回值。 int f(){    int i,ans=0;    for(i=1;i<=n;i++){        if(!pairs[i])            break;    }       //如果全部配对进行判断        if(i>n){        if(isOK())            return 1;        return 0;    }    for(int j=i+1;j<=n;j++){        if(!pairs[j]){            pairs[i]=j;            pairs[j]=i;            ans+=f();//i-j配对,并往下面递归 ,并将方法数加到ans上             pairs[i]=pairs[j]=0;        }    }    return ans;}int main(){    ifstream fin("wormhole.in");    ofstream fout("wormhole.out");    fin>>n;    for(int i=1;i<=n;i++){        fin>>p[i].x>>p[i].y;    }    //排序     sort(p+1,p+n+1,cmp);    //坐标预处理,记录编号i-1的虫洞的右边是否有虫洞,有就记录编号,没有就是0     for(int i=2;i<=n;i++){        if(p[i].y==p[i-1].y){            right_next[i-1]=i;        }    }    int ans=f();    fout<<ans<<endl;    fin.close();    fout.close();    return 0;}