wormhole-section1.3

题目大意

    农夫约翰爱好在周末进行高能物理实验的结果却适得其反,导致农场上产生了N个虫洞(2<=N<=12,n是偶数),每个在农场二维地图的一个不同点。
    根据他的计算,约翰知道他的虫洞将形成 N/2 连接配对。例如,如果A和B的虫洞连接成一对,进入虫洞A的任何对象体将从虫洞B出去,朝着同一个方向,而且进入虫洞B的任何对象将同样从虫洞A出去,朝着相同的方向前进。这可能发生相当令人不快的后果。
    例如,假设有两个成对的虫洞A(1,1) 和 B(3,1),贝茜从(2,1)开始朝着 +x 方向(右)的位置移动。贝茜将进入虫洞 B(在(3,1)),从A出去(在(1,1)),然后再次进入B,困在一个无限循环中!
| . . . .
| A > B .      贝茜会穿过B,A,
+ . . . .      然后再次穿过B
    农夫约翰知道他的农场里每个虫洞的确切位置。虽然他不记得贝茜的当前位置,但是他知道贝茜总是向着 +x 的方向走。请帮助农夫约翰计算不同的虫洞配对(情况),使贝茜可能从不幸的位置开始被困在一个无限循环中。
输入格式
第1行:N,虫洞的数目
第2到N+1行:每一行都包含两个空格分隔的整数,描述一个以(x,y)为坐标的单一的虫洞。每个坐标是在范围 0..1000000000。
输出格式
一个数字:会使贝茜从某个起始点出发沿+x方向移动卡在循环中的不同的配对。
样例输入
4
0 0
1 0
1 1
0 1
样例输出
2

题解

分为两步,第一步找出所有配对的方式,不能重复,更不能遗漏。显然不会是个全排列,因为每对的顺序无所谓,对于对之间的顺序也无所谓。本处的做法是,人为规定一个顺序,这样便不用考虑去重的问题:每对由两个元素构成,每对的第一个元素永远挑没有被挑走的第一个;每对的第二个元素依此向后挑(每对内均是小的在前大的在后,且每对与每对之间,每对的第一个元素是升序排列的)。过程如下:
6个元素,分成三组,元素依此为1 2 3 4 5 6;
以下是算法流程:
    1 2 ,3 4 ,5 6
    1 2 ,3 5 ,4 6
    1 2 ,3 6 ,4 5
    1 3 ,2 4 ,5 6
    1 3 ,2 5 ,4 6
    1 3 ,2 6 ,4 5
    1 4 ,2 3 ,5 6
    1 4 ,2 5 ,3 6
    1 4 ,2 6 ,3 5
    。
    。
    。
第二个问题是对于每种配对方式,怎样判断牛进入了无限循环:用step表示牛经过的虫洞个数,由于牛永远向一个方向走,所以牛走的路径是唯一的,如果牛第二次进入(不是经过,因为经过可能是离开)同一个虫洞,那么一定会陷入循环,所以当step>2*N的时候,一定陷入循环。

代码

#include<stdio.h>
int N,count=0,flag=0;
long int a[15][2];
int b[15][2];
int g(int step,int i)
{
int number,j,s;
number=b[i][1];
if(step>2*N)
{flag=1;return 0;}
else
{
for(j=0;j<N;j++)
{
    if(number==b[j][1]&&j!=i)
    {   s=j;break;}
}
for(j=0;j<N;j++)
{
    if(a[j][1]==a[s][1]&&a[j][0]>a[s][0])
    {
        g(step+1,j);
        break;
    }
}
}
return 0;
}
int f(int k)
{
    int i,j;
if(k==0)
{
    for(i=0;i<N;i++)
    {
        flag=0;
        g(0,i);
        if(flag==1)
            break;

    }
    if(flag==1)
        count++;
}
else
{

    for(j=0;j<N;j++)
    {
        if(b[j][1]==0)
        {
            b[j][1]=k/2;
            break;
        }

    }
    for(i=0;i<N;i++)
    {
        if(b[i][1]!=0)
            continue;
        else
        {
            b[i][1]=k/2;
            f(k-2);
            b[i][1]=0;
        }
    }
    b[j][1]=0;
}
return 0;
}
int main()
{       
scanf("%d",&N);
int i,j,temp;
for(i=0;i<N;i++)
{
    b[i][0]=i;
    b[i][1]=0;
}
//  b[0][1]=1;b[1][1]=1;
for(i=0;i<N;i++)
    scanf("%d %d",&a[i][0],&a[i][1]);
for(i=0;i<N;i++)
    for(j=0;j<N-1-i;j++)
    {
        if(a[j][1]>a[j+1][1])
        {
            temp=a[j][1];
            a[j][1]=a[j+1][1];
            a[j+1][1]=temp;
            temp=a[j][0];
            a[j][0]=a[j+1][0];
            a[j+1][0]=temp;
        }
    }
for(i=0;i<N;i++)
    for(j=0;j<N-1-i;j++)
    {
        if(a[j][1]==a[j+1][1])
        if(a[j][0]>a[j+1][0])
        {
            temp=a[j][1];
            a[j][1]=a[j+1][1];
            a[j+1][1]=temp;
            temp=a[j][0];
            a[j][0]=a[j+1][0];
            a[j+1][0]=temp;

        }
    }

    f(N);
//  g(0,1);
    printf("%d\n",count);

    for(i=0;i<N;i++)
        printf("%d %d\n",a[i][0],a[i][1]);
    return 0;

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值