UVA 11853(找连通块)

求连通块问题, 按照紫书上的思路, 构图(每一块受攻击区域作为一个结点)进行DFS, 若有一条路(攻击区域内)能够连通上下边则输出IMPOSSIBLE, 否则就分别计算最靠北(坐标值较大)的出入点.

整个区域是一个大的正方形. 求连通块比较简单, 从那些与区域上边相交的结点出发进行DFS, 若能够到达某一个与区域的下边相交的结点则说明上下边可以连通.

我觉得比较难的地方反倒在于找坐标值最大的出入点。比如求入点,比较容易想到的是遍历所有与正方形区域的左边相交的点,找出这条边上没有被覆盖的最大坐标就行了。但实现起来还是有些小细节要想好久。实际上不需要对所有与左边相交的点都检查一遍(过于繁琐),只要检查那些DFS路径走到过的而且与左边相交的结点即可。因为不在DFS路径中的结点与DFS过的结点之间必然有一些空隙, 有空隙就可以穿过, 因此不在其DFS路径中的结点不会对出入点造成影响。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <string>
#include <vector>
#include <set>
#include <stack>
#include <queue>
#include <deque>
#include <map>
#include <list>
#include <cassert>
#include <iomanip>


struct Point {
    double x, y;
    double range;
};

using namespace std;

bool isAvailable;

int N = 0;


Point pts[1002];
bool  G[1002][1002];
bool  isVisited[1002];
double in, out;


bool isInteract(int p1, int p2) {       // 判断是否相交, 是则返回true
    return (pts[p1].range + pts[p2].range) >=
            hypot(pts[p1].x - pts[p2].x, pts[p1].y - pts[p2].y);
}

void DFS(int i) {
    if ( !isAvailable ) return;
    if ( pts[i].y - pts[i].range <= 0 ) {
        isAvailable = false;
        return;
    }
    isVisited[i] = true;
    for ( int k = 0; k < N; k++){
        if (!isVisited[k] && G[i][k] ) {
            DFS(k);
        }
    }
    if ( pts[i].x <= pts[i].range )         // 应该只针对DFS路径中走过的区域计算出入点位置
                                            // 因为如果不在DFS路径中的区域与DFS过的区域之间必然有空隙, 有空隙就可以穿过
                                            // 因此不在DFS路径中的区域不会对出入点造成影响
        in = min(in,
                 pts[i].y - sqrt(pow(pts[i].range, 2) - pow(pts[i].x, 2)));
    if ( pts[i].x + pts[i].range >= 1000 )
        out = min(out,
                  pts[i].y - sqrt(pow(pts[i].range, 2) - pow(1000 - pts[i].x, 2)));
    return;
}


int main( ) {
    while ( cin >> N ) {
        isAvailable = true;
        in = out = 1000;
        memset(G, 0, sizeof(G));
        memset(pts, 0, sizeof(pts));
        memset(isVisited, 0, sizeof(isVisited));
        for ( int i = 0; i < N; i++ ) {
            cin >> pts[i].x >> pts[i].y >> pts[i].range;
            for ( int j = 0; j < i; j++ ) {
                if ( !G[i][j] && isInteract(i, j) ) {
                    G[i][j] = G[j][i] = true;
                }
            }
        }
        for ( int i = 0; i < N; i++ ) {
            if ( !isVisited[i] && pts[i].y + pts[i].range >= 1000 ) {
                DFS(i);
            }
        }
        if ( isAvailable ) {
            printf("0.00 %.2f 1000.00 %.2f\n", in, out);
        } else {
            cout << "IMPOSSIBLE" << endl;
        }
    }


    system("pause");
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值