解题思路
通过回溯求出所有组合,然后枚举每个入口进入后是否进入死循环;
解题步骤
1. 将虫洞排序(先按y坐标排, y坐标相同相同再排x坐标);
bool cmp(map c,map v)
{
if(c.y==v.y)
return c.x<v.x;
return c.y<v.y;
}
2.记录每个点t沿x轴方向右边最近的点,保存在next[t]中,若右边没有点,则next[t]=0(由于这里排过序了,所以可以线性查找);
for( int i=1 ; i<n ; i++ )
{
if(p[i].y<p[i+1].y;
next[i]=i+1;
}
3.回溯,求出n个数两两配对的所有组合,用数组a存,单双成对;
考虑到不能重复(比如12 34和12 43和34 12)这里的限制条件是:偶数位cs一定大于他的前一位cs-1,奇数位一定大于他的前面第二位cs-2;
cs>n时得到一组解
void hs(int cs)
{
if(cs>n)
{
for(int i=1;i<n;i+=2)
{
partner[a[i]]=a[i+1];
partner[a[i+1]]=a[i];
}
sum+=pd();
return;
}
if(cs%2!=0)
{
if(cs>1)
{
for(int i=a[cs-2];i<=n;i++)
{
if(book[i]==0)
{
book[i]=1;
a[cs]=i;
hs(cs+1);
book[i]=0;
}
}
return;
}
for(int i=1;i<=n;i++)
{
if(book[i]==0)
{
book[i]=1;
a[cs]=i;
hs(cs+1);
book[i]=0;
}
}
return ;
}
if(cs%2==0)
{
for(int i=a[cs-1]+1;i<=n;i++)
{
if(book[i]==0)
{
book[i]=1;
a[cs]=i;
}ok[i]=0;
}
}
return;
4.每得到一组解,进行判断:从每个点进去,模拟运动情况,判断是否会进入死循环;
int pd()
{
int flag=0;
for(int i=1;i<=n;i++)
{
memset(book2,0,sizeof(book2));
flag=enter(i);
if(flag==1)return 1;
}
return 0;
}
5.模拟从每个点进去的结果,不会循环返回0,会循环返回1;
int enter(int po)
{
int t=po;
int now=1;
while(1)
{
if(now==1)
{
book2[t]=1;
t=partner[t];
now=0;
}
if(now==0)
{
if(next[t]==0)
return 0;
t=next[t];
if(book2[t]==1)
return 1;
book2[t]=1;
now=1;
}
}
}