USACO训练场 1.4Wormholes

USACO训练场 1.4Wormholes

每天一道题+个人总结打卡
此博客仅用于记录学习

题目:
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 .
+ . . . .

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 \fBfind 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\fP). 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.

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

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

大致思路:
感觉这一题还挺有难度的,官方题解是真的厉害!!!
这题主要用到的还是深搜(dfs)吧。主要解决两个问题,1是怎么判断John被困住了,2是有几组wormholes的配对组合。然后只要枚举所有配对组合的情况,记录一下,再判断一下John会不会被困住(陷入循环)就OK了。
刚开始想的是开一个数组存已经去过的wormhole,如果一个wormhole去过两次,那么就证明John被困住了,然后交上去发现错了…因为有以下这种情况:
在这里插入图片描述

A和B是一对pair,C和D是一对pair,从A点进去,A->B,B->C,C->D,D->B(B点已经来过一次了),B->A(A也来过一次了),虽然A和B都经过两次,但是这并不会陷入循环。后面才想到判断是否陷入死循环只需要判段与目前点配对的另一个点的右边最近一个点是不是起始点就OK了,如果是起始点,说明陷入了死循环。
寻找配对组合的时候,可以用个数组标记一下该点是否已有配对,用dfs来进行配对,函数返回的时候记得把这个标记删掉。官方题解直接用记录配对对象的数组来判断该点是否已有配对,这种方法更简洁,我还多开了一个数组专门记录这个点是否已经配对,其实可以直接用记录配对对象的数组来判断。

代码:

#include <bits/stdc++.h>
#include <fstream>
#include <string>
using namespace std; 
int N;
struct Node
{
 int x;
 int y;
 int cnt;
};
Node P[20];
int vis[20];
int ans;
int jud;
int rec[20];
bool cmp(Node a,Node b)
{
	 return a.x<b.x;
}
void check()
{
	  for(int i=1;i<=N;i++)//枚举每一个点 
	  {  
		   jud=0;
		   int pos=i;
		   vis[i]=1;
		  
	   while(1)
	   {
	    	pos=P[pos].cnt;//与pos配对的点 
	    
	    	for(int i=1;i<=N;i++)
	    	{
	     	if(P[i].y==P[pos].y&&P[i].x>P[pos].x)//同一行右边最近的点 
	    	 {
	   	   pos=i;
	   	   jud=1;//如果jud==0的话,说明右边没有点了,那么这组情况不会陷入死循环 
	     	 break;
	     	}
	    }
	   
	    if(jud==0) 
	     	break;
	    else
	    	 jud=0;
	   
	    if(vis[pos]==1)//右边这个点是起始点,那么说明陷入了死循环 
	    {
	     	jud=1;
	     	break;
	    } 
	   }
	   if(jud==1)
	   	 break;
	    
	   vis[i]=0;
	    
	  }
	  if(jud==1)
	   	ans+=1;
	   
	  memset(vis,0,sizeof(vis));
}
void dfs(int a,int b,int num)
{
	rec[a]=1;
	 rec[b]=1;
	 P[a].cnt=b;//记录配对对象 
	 P[b].cnt=a;
	 if(num==N/2)//满足了配对 
	 {
	  check();//判断是否陷入死循环 
	  return;
	 }
	for(int i=1;i<=N;i++)
	{
  		if(rec[i]==1)
  		 continue;
  		 for(int j=1;j<=N;j++)
	  	{
	   		if(rec[j]==0&&i!=j)
	   		{
	   			 dfs(i,j,num+1);
	   			 rec[j]=0;
	   			 rec[i]=0;
	   		}
	  	}
	  	break;
	 }
}
int main()
{
	 ofstream fout ("wormhole.out");
	    ifstream fin ("wormhole.in");
	    
	    fin>>N;
	    for(int i=1;i<=N;i++)
	     	fin>>P[i].x>>P[i].y;
	     
	 sort(P+1,P+1+N,cmp);//按x值从小到大排序 
	 
	 for(int i=2;i<=N;i++)
	 {
	  	dfs(1,i,1);
	  	rec[1]=0;
	  	rec[i]=0;
 	}
	 fout<<ans<<endl; 
}
				

官方题解:

#include<bits/stdc++.h>
using namespace std;
int N;
struct Node
{
 int x;
 int y;
 int cnt;
};
Node P[20];
int rt[20];
bool cmp(Node a,Node b)
{
 	return a.x<b.x;
}
int check()
{
	 int pos=0;
	 for(int i=1;i<=N;i++)//枚举每个点 
	 {
	 	 pos=i;
	 	 for(int j=0;j<N;j++)//循环N次,肯定能判断是否陷入循环,在不陷入死循环的情况下,遍历完所有点最多也只需要N次 
	           pos=rt[P[pos].cnt];
	   
	  	if(pos!=0)//陷入了循环 
	   	   return 1;
	 }
	 return 0;
}
int dfs()
{
	 int i=0,j=0;
	 int ans=0;
	 
	 for(i=1;i<=N;i++)
	  	if(P[i].cnt==0)
	  		 break;
	   if(i>N)//所有点都有了配对 
	 {
	  	if(check()==1)//判断是否会陷入死循环 
	   		return 1;
	 }
	 
	 for(j=i+1;j<=N;j++)
	 {
	 	 if(P[j].cnt==0)//说明未配对 
	 	 {
	   		P[j].cnt=i;
	   		P[i].cnt=j;
	   		ans+=dfs();
	   		P[i].cnt=P[j].cnt=0;
  		}
 	}
 	return ans;
}
int main()
{
	 cin>>N;
	 for(int i=1;i<=N;i++)
	 {
	 	 cin>>P[i].x>>P[i].y;
	 }
	 sort(P+1,P+1+N,cmp);//按x值从小到大排序 
	 
	 //先记录每个点右边最近的一个点 
	 for(int i=1;i<=N;i++)
	 {
	  	for(int j=1;j<=N;j++)
	  	{
	  		if(P[i].y==P[j].y&&P[j].x>P[i].x)
	  		 {
	   		 	rt[i]=j;
	    			break;
	   		}
	  	}
	 }
     
 	cout<<dfs()<<endl;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值