第一场-K-Keeping the Dogs Apart

本文解析了一道关于两只小狗在不同路径上移动时如何计算它们之间最短距离的问题。通过设定速度并简化为线段距离问题,利用数学方法求解最小距离。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:点击打开链接

(一)题目大意:有两只可爱的小狗分别从两个点出发沿一定的路线运动,对于每一只小狗的路线:依此给出若干个点,该小狗依次沿直线从一个点走到下一个点,已知两只小狗同时出发,且速度相等,求两只小狗在运动过程中距离的最小值(当其中一只狗到达终点时,狗狗之间的距离不再需要考虑)。

(二)解题思路:

  1. 首先我们可以直接设速度为v=1。
  2. 由于小狗在每一段的运动轨迹均为直线,我们可以把原问题化为求若狗在线段对上运动时狗之间的最短距离。
(三)细节说明:
(这里假设狗狗分别为A,B,当前A从n1走到n2,B从n3走到n4,l1=dist(n1,n2),l2=dist(n3,n4))。
  1. 若l1==l2,则两只狗狗都刚好走完当前线段。
  2. 若l1<l2,则先求出当A走到n2时,B走到的点tmp,再求狗线段对n1-n2与n3-tmp上运动时的最短距离。
  3. 若l1>l2,类似上一种方法处理。
  4. 不断更新A和B运动时的起点和终点。

然后就是要处理两只狗在线段对上运动时的最短距离:
        假设运动时间为t,我们可以求出t时刻A和B的坐标,然后便可以得到一个距离关于时间t的函数,形如d=a*t*t+b*t+c的形式。然后讨论一下a的取值以及t是否能取到最值即可以得出距离的最小值。简略过程如下:


(四)具体代码:
#include<iostream>
#include<cstring>
#include<string>
#include<vector>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
struct node{
    double x,y;
}p1[maxn],p2[maxn];
inline double dist(node n1,node n2){                              //距离
    return sqrt((n1.x-n2.x)*(n1.x-n2.x)+(n1.y-n2.y)*(n1.y-n2.y));
}
node getn(node n1,node n2,double l){                              //得到中间点
    node n3;
    double len=dist(n1,n2);
    double ex1=(n2.x-n1.x)/len,ey1=(n2.y-n1.y)/len;
    n3.x=n1.x+ex1*l;
    n3.y=n1.y+ey1*l;
    return n3;
}
double getdist(node n1,node n2,node n3,node n4){                  //求运动时的距离
    double L1=dist(n1,n2),L2=dist(n3,n4);

    double ex1=(n2.x-n1.x)/L1,ey1=(n2.y-n1.y)/L1;                 //方向向量
    double ex2=(n4.x-n3.x)/L2,ey2=(n4.y-n3.y)/L2;

    double a=(ex1-ex2)*(ex1-ex2)+(ey1-ey2)*(ey1-ey2);             //式子中的a,b,c
    double b=2.0*((n1.x-n3.x)*(ex1-ex2)+(n1.y-n3.y)*(ey1-ey2));
    double c=(n1.x-n3.x)*(n1.x-n3.x)+(n1.y-n3.y)*(n1.y-n3.y);

    if(a==0)  return min(dist(n1,n3),dist(n2,n4));                //分类讨论
    double t=-b/(2.0*a);
    if(t<0||t>L1)return min(dist(n1,n3),dist(n2,n4));
    return sqrt(a*t*t+b*t+c);
}
int main(){
    int n,m;
    scanf("%d",&n);
    for(int i=0;i<n;i++)scanf("%lf%lf",&p1[i].x,&p1[i].y);
    scanf("%d",&m);
    for(int i=0;i<m;i++)scanf("%lf%lf",&p2[i].x,&p2[i].y);
    int i=1,j=1;
    double _min = 1e9;
    while(j<m&&i<n){                                              //不断更新运动端点求解
        double l1=dist(p1[i-1],p1[i]),l2 =dist(p2[j-1],p2[j]);
        if(l1 == l2){
            _min=min(_min,getdist(p1[i-1],p1[i],p2[j-1],p2[j]));
            ++i,++j;
        }
        else if(l1<l2){
            node tmp=getn(p2[j-1],p2[j],l1);
            _min=min(_min,getdist(p1[i-1],p1[i],p2[j-1],tmp));
            ++ i;
            p2[j-1] = tmp;
        }
        else{
            node tmp=getn(p1[i-1],p1[i],l2);
            _min=min(_min, getdist(p1[i-1],tmp,p2[j-1],p2[j]));
            ++ j;
            p1[i-1]=tmp;
        }
    }
    printf("%.10lf\n", _min);
    return 0;
}

这tm还是一个模拟题以及一点点数学姿势?(气的是当时把题目看错然后撸了四五十分钟的代码 敲打...)

<think>好的,我现在需要帮助用户理解如何在冻结的预训练模型上仅训练新的线性分类器,同时保持原模型参数不变。首先,我需要回忆一下相关的知识,比如迁移学习中常用的方法,冻结预训练模型参数的原因,以及如何添加新的层进行训练。 用户提到的引用中有几处可能相关的信息。引用[3]提到通过更改预先训练的模型,比如密集网,但需要更多的训练时间,同时需要进一步预处理图像。这可能涉及到在预训练模型基础上进行微调或添加新层。引用[4]中的反向传播算法和批量训练,说明在训练过程中如何调整权重,但这里需要确保原模型的权重不被更新。 首先,用户的问题是如何在冻结的预训练模型上训练新的线性分类器。步骤可能包括:加载预训练模型,冻结其所有参数,添加新的线性分类层,然后只训练这个新层。需要确保在反向传播时,预训练模型的参数梯度不被计算和更新。 接下来,我需要考虑具体实现方式,比如在PyTorch或TensorFlow中如何操作。例如,在PyTorch中,可以通过设置requires_grad=False来冻结参数,然后定义新的分类器层,并将优化器仅应用于新层的参数。同时,预处理步骤可能也很重要,如引用[3]提到的图像预处理,需要确保输入数据符合预训练模型的要求。 可能还需要解释为什么这样做有效。预训练模型已经提取了有用的特征,冻结参数可以防止过拟合,特别是在数据量较少的情况下。新添加的线性分类器则根据特定任务调整决策边界,而无需重新训练整个模型。 用户可能还关心这种方法的应用场景、优缺点,以及如何进一步优化。例如,如果新任务的数据分布与预训练数据差异较大,可能需要部分解冻底层进行微调,但根据用户要求,这里必须保持原参数不变。此外,可能需要调整学习率,因为新层的训练可能需要不同的学习速率。 最后,根据用户提供的引用,特别是引用[3]和[4],需要确保在训练过程中,错误传播仅影响新分类器的权重,而不影响冻结层。这涉及到在反向传播时,梯度只更新新添加层的参数,而预训练模型的梯度被忽略。引用[4]中提到的误差分配和权重调整应仅限于新层。 总结步骤应该是:加载模型、冻结参数、添加分类器、设置优化器仅更新新层、进行训练。同时,注意数据预处理和可能的学习率调整。验证方法是否有效,比如观察只有新层的参数在训练过程中变化,而原模型参数保持不变。</think>在冻结的预训练模型上仅训练新的线性分类器,是一种典型的迁移学习方法。以下是具体步骤和原理: ### 1. 模型结构与参数冻结 - **加载预训练模型**:例如使用ResNet、BERT等已训练好的模型 - **冻结参数**:将预训练模型的所有参数设置为不可训练状态 在PyTorch中: ```python for param in pretrained_model.parameters(): param.requires_grad = False ``` 在TensorFlow中: ```python pretrained_model.trainable = False ``` ### 2. 添加新分类器 - **线性分类层**:通常在模型末端添加全连接层 例如对图像分类任务: ```python new_classifier = nn.Sequential( nn.Flatten(), nn.Linear(pretrained_feature_dim, num_classes) ) ``` 此时只有`new_classifier`的参数会被更新[^3] ### 3. 训练配置 - **优化器设置**:仅对新层参数进行优化 ```python optimizer = torch.optim.Adam(new_classifier.parameters(), lr=1e-3) ``` - **损失函数**:根据任务选择交叉熵损失等 - **数据预处理**:需与预训练模型的输入规范一致[^3] ### 4. 训练过程 通过前向传播时,输入数据先经过冻结的预训练模型提取特征,再进入新分类器: ``` 输入数据 → 冻结的预训练模型 → 特征向量 → 新分类器 → 输出 ``` 反向传播时误差仅作用于新分类器的权重调整[^4]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值