Codeforces Gym 101174 K. Balls and Needles (DFS)

11 篇文章 0 订阅

Problem

给定 K 组三维线段 x1 y1 z1 x2 y2 z2 ,判断是否存在 3 条边构成环。同时将三维线段投射到二维平面上,构成若干二维线段 x1 y1 x2 y2 (可能有重合),判断是否存在 3 条二维线段构成环。

限制条件

1 ≤ K ≤ 50000

1xi, yi, zi1000

解题思路

通过离散化将三维点和二维点作为点编号,记录二维线段和三维线段(通过两端点的编号形式保存)。DFS 深搜,标记遍历到的点的深度,若存在已记录深度的点的深度较之再次遍历到该点的深度差 2 。则存在对应维度的环。

代码

#include<bits/stdc++.h>
using namespace std;
struct Node {
    int x, y, z;
} p, q;
bool operator<(Node a, Node b) {
    if(a.x == b.x) {
        if(a.y == b.y)  return a.z < b.z;
        return a.y < b.y;
    }
    return a.x < b.x;
}
map<Node, int> d2, d3;
int K, d2idx, d3idx, vis[2][100010];
vector<int> g[2][100010];
bool isLink[2];
void dfs(int lv, int rt, int dep)
{
    if(isLink[lv])  return;
    vis[lv][rt] = dep;
    for(int i=0;i<g[lv][rt].size();i++)
    {
        if(vis[lv][ g[lv][rt][i] ]) {
            if(dep - vis[lv][g[lv][rt][i]] >= 2) {  isLink[lv] = true;  return; }
            continue;
        }
        dfs(lv, g[lv][rt][i], dep+1);
    }
}
int main()
{
    scanf("%d", &K);
    for(int i=1;i<=K;i++)
    {
        scanf("%d %d %d %d %d %d", &p.x, &p.y, &p.z, &q.x, &q.y, &q.z);
        if(d3.find(p) == d3.end())  d3[p] = ++d3idx;
        if(d3.find(q) == d3.end())  d3[q] = ++d3idx;

        g[1][ d3[p] ].push_back(d3[q]);
        g[1][ d3[q] ].push_back(d3[p]);

        p.z = q.z = 0;
        if(d2.find(p) == d2.end())  d2[p] = ++d2idx;
        if(d2.find(q) == d2.end())  d2[q] = ++d2idx;

        g[0][ d2[p] ].push_back(d2[q]);
        g[0][ d2[q] ].push_back(d2[p]);
    }

    for(int i=1;i<=d3idx;i++)
    {
        if(vis[1][i])   continue;
        dfs(1, i, 1);
    }

    for(int i=1;i<=d2idx;i++)
    {
        if(vis[0][i])   continue;
        dfs(0, i, 1);
    }

    printf("%s\n%s\n", isLink[1]?"True closed chains":"No true closed chains", 
           isLink[0]?"Floor closed chains":"No floor closed chains");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值