1352. 虫洞

首先将所有点按纵坐标从小到大排序,纵坐标相同的按横坐标从小到大排序,这样一来,每个点+x方向上最近的点(若存在)在排序后的数组宏一定相邻。

DFS搜索与当前点匹配的点,若当前点已经配对,则搜下一个点;若没有配对,则寻找还没有配对的点与当前点配对。

之后分别以每个点为起点进行DFS判环(每次判环前需要清空标记数组),判断是否会重复访问某一节点。注意走到虫洞时,应该立马传送到到与该虫洞配对的点上,而不能停留在这个点。

注意点

  • 贝茜会一直沿着 x 轴正向移动,但是她当前的位置约翰并不清楚,所以需要枚举以所有点为起点进行判环。
  • 贝茜一旦遇到虫洞则必须进入。
  • 虫洞间是无向边,而每个点与+x方向最近的点间是有向边,但稍加分析后会发现,如果上一次是从虫洞走来的,这次必然步行;如果上一次是步行来的,这次必然走虫洞。
const int N=15;
PII a[N];
int r[N],paired[N];
bool vis[N];
int n;
int ans;

bool cycle(int u)
{
    if(vis[u]) return true;
    vis[u]=true;

    if(r[u]) return cycle(paired[r[u]]);
    else return false;
}

void dfs(int u)
{
    if(u > n)
    {
        bool ok=false;
        for(int i=1; i <= n; i++)
        {
            memset(vis,0,sizeof vis);
            if(cycle(i))
            {
                ok=true;
                break;
            }
        }

        if(ok) ans++;
        return;
    }

    if(paired[u]) dfs(u+1);
    else
    {
        for(int i=u+1; i<=n; i++)
            if(!paired[i])
            {
                paired[u]=i,paired[i]=u;
                dfs(u+1);
                paired[u]=paired[i]=0;
            }
    }
}

int main()
{
    cin>>n;

    for(int i=1;i<=n;i++) cin>>a[i].fi>>a[i].se;

    sort(a+1,a+n+1,[](PII a, PII b){
         if(a.se != b.se) return a.se < b.se;
         return a.fi < b.fi;
    });

    for(int i=1;i<n;i++)
        if(a[i].se == a[i+1].se)
            r[i]=i+1;

    dfs(1);

    cout<<ans<<endl;
    //system("pause");
    return 0;
}
原文地址:https://www.cnblogs.com/fxh0707/p/14760057.html