usaco 虫洞 洛谷

问题描述:李宗泽的爱好是在周末进行物理学实验,但事与愿违,实验将N个黑洞(2 <= N <= 12, N为even)具象化在了他的农场里,每个都有明确的坐标位置。根据他的计算,李宗泽知道将会形成N/2对连接起来的黑洞。如果黑洞A和B被连成一对,那么任何物体进入黑洞A,将会以进入黑洞A的方向从黑洞B中出来;进入黑洞B,也会以进入时的方向从黑洞A中出来。举例来说,黑洞A在(0,0),黑洞B在(1,0),牛玉鑫从(1/2,0)开始向X轴正方向移动,进入黑洞B,从黑洞A中出来,将继续向X轴正方向移动,再次进入黑洞B,被困在一个循环里。李宗泽知道每一个黑洞在他的农场上的具体坐标,牛玉鑫只会向X轴正方向移动,但却不知道牛玉鑫目前的位置。请你帮助李宗泽计算共有多少种黑洞配对方法会使在不幸的位置的牛玉鑫陷入循环。

输入说明:第一行:一个正整数N;第二到N+1行:每行两个整数X,Y描述一个黑洞的位置,每个坐标在0..1,000,000,000内。

样例输入:(wormhole.in)


4

0 0

1 0

1 1

0 1

有4个黑洞,形成一个正方形的循环。

输出说明:第一行:一个数,代表所有的会让牛玉鑫陷入循环的黑洞配对方法数。

样例输出:(file wormhole.out)

2

给这4个黑洞编号为1..4。如果将1和2相连,3和4相连,牛玉鑫从1和2之间或3和4之间出发时会陷入循环。相同的,如果连接1和3,2和4,牛玉鑫也会陷入循环。只有连接1和4,2和3,牛玉鑫从任何一个位置开始移动都不会陷入循环。

思路:先枚举所有的匹配方式,然后匹配完之后dfs搜找环,具体见代码

#include<bits/stdc++.h>
using  namespace  std;
int n;
struct node
{
	int x,y;
}a[30];
int b[30];
int ans;
bool mycmp(node xx,node yy)
{
	if(xx.y=yy.y) return xx.x<yy.x;//以纵坐标为第一关键字,横坐标为第二关键字进行排序 
	return xx.y<yy.y;
}
int dfs(int num,int d,int begin,int flag)//num是标记  begin标记是否回到原点
//flag==1:以走的方式到达点d   flag==0:从某虫洞到达点d 
{
	if(num!=1 &&d==begin &&flag==1) return 1;//回到原点,并且是以走的方式到达 
	if(flag==0)//从虫洞d出来,就往前走,如果前面有虫洞,就走过去,没有就返回0 
	  {
	  	if(a[d].y==a[d+1].y) return dfs(num+1,d+1,begin,1);
	  	else                 return 0;//没有形成环就返回0 
	  }
	if(flag==1) return dfs(num+1,b[d],begin,0);//走到虫洞口就跳进去 
}
bool check()
{
	for(int i=1;i<=n;i++)//尝试从每个点出发看是否形成环 
	  if(dfs(1,i,i,1)==1) return 1;//有一个就返回1 
	return 0;
}
void partner(int x)//配对 
{
	if(x==n+1)
	  {
	  	if(check()==1) ans++;return;//n个点都匹配完,就检查 
	  }
	if(b[x]==0)//x没有匹配 
	  {
	  	for(int i=x+1;i<=n;i++)//一个一个搜 
	  	  if(b[i]==0)
	  	    {
	  	    	b[i]=x;
				b[x]=i;//互相匹配 
	  	    	partner(x+1);//继续往后匹配 
	  	    	b[i]=0;
	  	    	b[x]=0;//恢复原状 
	  	    }
	  	  
	  }
	if(b[x]!=0) partner(x+1);//x匹配过了,继续往后匹配 
	return;
}
int  main()
{
  scanf("%d",&n);
  for(int i=1;i<=n;i++)
    {
      scanf("%d %d",&a[i].x,&a[i].y);
    }
  sort(a+1,a+1+n,mycmp);
  partner(1);
  printf("%d",ans);
  return 0;
}

提供原网址:点击打开链接

代码参考 redbag



                
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值