LOI2504 [HAOI2006]聪明的猴子

探讨猴子在被洪水覆盖的雨林中如何利用其跳跃能力在树冠间觅食的问题,通过构建最小生成树模型来计算有多少只猴子能够到达所有露出水面的树冠。

题目描述

在一个热带雨林中生存着一群猴子,它们以树上的果子为生。昨天下了一场大雨,现在雨过天晴,但整个雨林的地表还是被大水淹没着,部分植物的树冠露在水面上。猴子不会游泳,但跳跃能力比较强,它们仍然可以在露出水面的不同树冠上来回穿梭,以找到喜欢吃的果实。
现在,在这个地区露出水面的有N棵树,假设每棵树本身的直径都很小,可以忽略不计。我们在这块区域上建立直角坐标系,则每一棵树的位置由其所对应的坐标表示(任意两棵树的坐标都不相同)。
在这个地区住着的猴子有M个,下雨时,它们都躲到了茂密高大的树冠中,没有被大水冲走。由于各个猴子的年龄不同、身体素质不同,它们跳跃的能力不同。有的猴子跳跃的距离比较远(当然也可以跳到较近的树上),而有些猴子跳跃的距离就比较近。这些猴子非常聪明,它们通过目测就可以准确地判断出自己能否跳到对面的树上。
【问题】现已知猴子的数量及每一个猴子的最大跳跃距离,还知道露出水面的每一棵树的坐标,你的任务是统计有多少个猴子可以在这个地区露出水面的所有树冠上觅食。

分析

最小生成树模型

#include <bits/stdc++.h>
#define rep( i , l , r ) for( int i = (l) ; i <= (r) ; ++i )
#define per( i , r , l ) for( int i = (r) ; i >= (l) ; --i )
#define erep( i , u ) for( int i = head[(u)] ; ~i ; i = e[i].nxt )
using namespace std;
int _read(){
    char ch = getchar();
    int x = 0 , f = 1 ;
    while( !isdigit( ch ) )
           if( ch == '-' ) f = -1 , ch = getchar();
           else ch = getchar();
    while( isdigit( ch ) )
           x = (ch  - '0') + x * 10 , ch =  getchar();
    return x * f;
}
const int maxn = 1000 + 5 , maxm = 2500000 + 5;
struct edge{
    int u , v , w;
} e[maxm];
#define PII pair<int,int>
#define FR first
#define SE second
PII a[maxn];
int f[maxn] , _t = 0;
int get_f( int x ){
    if( f[x] == x ) return x;
    else return f[x] = get_f( f[x] );
}
inline bool cmp( const edge &a , const edge &b ){
    return a.w < b.w;
}
const int INF = 0x7f7f7f7f;
int dis[maxn];
int main(){
    int M = _read();
    rep( i , 1 , M ) dis[i] = _read();
    int N = _read();
    rep( i , 1 , N ){
        a[i].FR = _read() , a[i].SE = _read();
        rep( j , 1 , i - 1 ){
            int w = (a[i].FR - a[j].FR) * (a[i].FR - a[j].FR) 
                 +  (a[i].SE - a[j].SE) * (a[i].SE - a[j].SE);
            _t++; e[_t].u = i , e[_t].v = j , e[_t].w = w;
        }
    }
    sort( e + 1 , e + _t + 1 , cmp );
    rep( i , 1 , N ) f[i] = i;
    int ans = 0;
    rep( i , 1 , _t ){
        int fx = get_f( e[i].u ) , fy = get_f( e[i].v );
        if( fx == fy ) continue;
        f[fx] = fy;
        ans = e[i].w;
    }
    int res = 0;
    rep( i , 1 , M )
        if( dis[i] * dis[i] >= ans ) ++res;
    cout << res << endl;    
    return 0;
}
### LOI Pooling 的概念与实现 LOI (Line of Interest) Pooling 是一种受目标检测领域中的 RoI (Region of Interest) Pooling 和 RoI Align 启发而设计的操作方法。其主要目的是在线段检测任务中,将线段映射到特征图上并生成固定大小的特征表示[^2]。 #### 背景 在计算机视觉任务中,尤其是涉及线段或边缘结构的任务(如 LCNN 中的线框分析),需要一种机制来提取特定区域内的特征并向主干网络传递梯度。传统的卷积神经网络通常会丢失空间信息,因此引入了类似于 RoI Pooling 或 RoI Align 的操作,用于处理感兴趣区域的特征提取问题。LOI Pooling 则专门针对线段这一几何对象进行了优化。 --- #### 基本概念 LOI Pooling 将一条线段视为一个兴趣区域,并将其投影到 CNN 提取的特征图上。具体来说,它通过以下方式工作: 1. **输入准备**:给定一张图像及其对应的特征图 \( F \),以及一组待检测的线段坐标集合 \( L = \{l_1, l_2, ..., l_n\} \)。 2. **线段投影**:每条线段被投影到特征图的空间维度上,形成一个新的采样路径。 3. **特征聚合**:沿着这条路径采集特征值,并通过插值或其他技术生成固定的特征向量。 这种操作使得模型能够在保持高精度的同时高效地学习线段特征。 --- #### 实现细节 以下是 LOI Pooling 的典型实现流程: ##### Step 1: 定义线段范围 假设有一条线段由两个端点定义为 \( p_s(x_s, y_s), p_e(x_e, y_e) \),则该线段可以通过参数化方程描述为: \[ P(t) = (1-t)p_s + t p_e,\quad t \in [0, 1]. \] 此方程允许我们在连续域内计算任意位置上的像素坐标。 ##### Step 2: 投影至特征图 由于原始图像经过多次下采样后形成了低分辨率的特征图,需将线段两端点 \( p_s, p_e \) 映射到特征图对应的位置 \( q_s(u_s, v_s), q_e(u_e, v_e) \)[^2]。这一步骤可通过简单的缩放变换完成。 ##### Step 3: 插值采样 沿投影后的线段路径,在特征图上进行双线性插值以获取精确的特征值。设某时刻 \( t_i \) 对应于特征图上的浮点坐标 \( (u_t, v_t) \),那么附近的四个整数网格点可参与加权平均运算,最终得到当前点处的特征值[^2]。 ##### Step 4: 特征重组 最后,将所有采样的特征按顺序排列成一维向量作为输出结果。如果存在多个通道,则分别独立执行上述过程后再拼接在一起[^2]。 ```python import torch from torchvision.ops import roi_align as _roi_align def loi_pooling(features, lines, output_size=16): """ Implementation of Line-of-Interest (LoI) Pooling. Args: features (Tensor): Feature maps from backbone network with shape (B, C, H, W). lines (List[Tuple]): List of line segments defined by start and end points [(xs, ys, xe, ye)]. output_size (int): Number of samples along each LoI. Returns: Tensor: Extracted feature vectors for all given lines. """ batch_size, num_channels, height, width = features.shape pooled_features = [] for b in range(batch_size): for xs, ys, xe, ye in lines[b]: # Normalize coordinates to ROIAlign format boxes = torch.tensor([[b, min(xs, xe), min(ys, ye), max(xs, xe), max(ys, ye)]], dtype=torch.float).cuda() # Perform ROI Align on the box containing the line segment aligned_feature = _roi_align(features[[b]], boxes, (output_size, 1)) # Reshape into a vector pooled_features.append(aligned_feature.squeeze().view(num_channels, -1)) return torch.stack(pooled_features) # Example usage features = torch.randn((2, 256, 64, 64)).cuda() # Batch size 2, channels 256, spatial dims 64x64 lines = [[(10, 10, 50, 50)], [(20, 20, 70, 70)]] # Two batches, one line per image result = loi_pooling(features, lines) print(result.shape) # Output should be (number_of_lines, channel_dim * output_size) ``` --- #### 总结 LOI Pooling 结合了几何先验知识和深度学习的优势,适用于各种基于线段建模的应用场景。相比传统的方法,它的灵活性更高且更容易集成到现代框架之中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值