题目链接:USACO-Wormholes
题意是给定n<=12个点,要求对于所有的两两配对的方案,找出能使牛陷入循环的方案。
解法是枚举所有的方案,然后进行检测。如果一个虫洞进入的次数大于1次,则陷入循环。
枚举可以通过递归来实现。
在递归的过程中,对于一个还没有匹配的点,他一定匹配编号比他大的点。
然后这样就可以保证同一种配对仅能出现一次。
/*
ID: xdujlx1
PROG: wormhole
LANG: C++
*/
#include<bits/stdc++.h>
using namespace std;
int x[20],y[20],b[20],r[20];
bool vis[20];
int n;
int cnt;
void ioinit()
{
freopen("wormhole.in","r",stdin);
freopen("wormhole.out","w",stdout);
}
bool isloop(int u)
{
memset(vis,0,sizeof(vis));
bool flag=true;
vis[u]=true;
while(1)
{
if(flag) u=b[u],flag=false;
else
{
if((u=r[u])==-1) return false;
if(vis[u]) return true;
vis[u]=true;
flag=true;
}
}
}
bool check()
{
for(int i=0;i<n;i++)
{
if(isloop(i)) return true;
}
return false;
}
void solve(int k)
{
if(k>=n&&check()) cnt++;
if(k>=n) return;
if(b[k]==-1)
{
for(int i=k+1;i<n;i++)
{
if(b[i]==-1)
{
b[i]=k;
b[k]=i;
solve(k+1);
b[i]=b[k]=-1;
}
}
}
else solve(k+1);
}
int main()
{
ioinit();
cnt=0;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d%d",&x[i],&y[i]);
memset(r,-1,sizeof(r));
int d[20];
memset(d,0x3f,sizeof(d));
for(int i=0;i<n;i++)
{
for(int j=0;j<n;j++)
{
if(y[i]==y[j]&&x[i]<x[j]&&x[j]<d[i])
r[i]=j,d[i]=x[j];
}
}
//for(int i=0;i<n;i++) printf("%d\n",r[i]);
memset(b,-1,sizeof(b));
solve(0);
printf("%d\n",cnt);
return 0;
}