P1444 [USACO1.3]虫洞 wormhole(判环dfs&&暴力枚举)

题目描述

Farmer John 周末进行高能物理实验的结果却适得其反,导致 nn 个虫洞出现在农场上,农场是一个二维平面,没有两个虫洞处于同一位置。

根据他的计算,FJ 知道他的虫洞两两配对,形成 n 2 \dfrac{n}{2} 2n 对配对。例如,如果 AA 和 BB 的虫洞连接成一对,进入虫洞 AA 的任何物体将从虫洞 BB 出去,方向不变;反之亦然。

然而这可能发生相当令人不快的后果。例如,假设有两个成对的虫洞 A(1,1) 和 B(3,1),Bessie 从 (2,1) 开始朝着 x 正方向移动。Bessie 将进入虫洞 B(3,1),从A(1,2) 出去,然后再次进入 B,困在一个无限循环中!

FJ 知道他的农场里每个虫洞的确切位置。他知道 Bessie 总是向 x 正方向走进来,虽然他不记得贝茜的当前位置。

请帮助 FJ 计算有多少种虫洞配对方案,使得存在一个位置,使得 Bessie 从该位置出发,会被困在一个无限循环中。

  • 输入格式
    第一行一个正整数 n,表示虫洞数量。

接下来 n 行,每行两个整数 x,y,表示一个虫洞的坐标。

  • 输出格式
    输出一行一个整数表示答案。

思路:

  • 先暴搜出所有的可能答案
  • 之后跑基环树的dfs来判环
int cur[N]//当前调用栈
int vis[N]//当前点是否被访问过

AC

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 20;
int n;
struct Point{
    int x, y;
    bool operator<(const Point& a)const {
        if(y != a.y)return y < a.y;
        return x < a.x;
    }
} p[N];
int e[N][2];
int ans = 0;
bool st[N];
bool used[N][2], cur[N][2];
bool dfs(int a, int x){
    if(cur[a][x]) return true;
    if(used[a][x]) return false;
    
    used[a][x] = cur[a][x] = 1;
    bool res = false;
   if(e[a][x^1] != -1)res = dfs(e[a][x^1],x^1);
    cur[a][x] = 0;
    return res;
}
bool check(){
    memset(used, 0, sizeof used);
    memset(cur, 0, sizeof cur);
    for(int i = 0; i < n; i ++ )for(int j = 0; j < 2; j ++ ){
        if(!used[i][j]){
            if(dfs(i,j))return true;
        }
    }
    return false;
}
void dfs(int x){
    if(x >= n/2){
        if(check())ans++;
        return ;
    }
    for(int i = 0; i < n; i ++ ){
        if(!st[i]){
            for(int j = 0; j < n; j ++ ){
                if(j == i || st[j]) continue;
                st[i] = st[j] = true;
                e[j][0] = i; e[i][0] = j;
                dfs(x+1);
                st[i] = st[j] = false;
                e[j][0] = -1; e[i][0] = -1;
            }
            break;
        }
    }
}
int main(){
    ios::sync_with_stdio(0);
    cin>>n;
    for(int i = 0; i < n; i ++ )cin>>p[i].x>>p[i].y;
    sort(p,p+n);
    for(int i = 0; i < n; i ++ )e[i][0] = e[i][1] = -1;
    for(int i = 1; i < n; i ++ )if(p[i].y == p[i-1].y)e[i-1][1] = i;
    dfs(0);
    cout<<ans<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值