Luogu P1337 [JSOI2004]平衡点 / 吊打XXX 77分题解

题目描述详见https://www.luogu.org/problemnew/lists?name=%E5%B9%B3%E8%A1%A1%E7%82%B9

此题方法灵感源于感知器学习算法。简而言之,就是随机选取数据,然后计算和期望结果相比的损失,在以损失值乘上学习率,更新到数据上。学习率越大,学习速度,也就是调整至期望结果的速度越快,但精度越低。学习率越小,精度越高,但学习时间也越长。所以要选取合适的学习率。时间复杂度没有具体分析过,不过个人实现的分类器在学习率为0.001时训练次数大约为数百万次,耗时几秒,OI中可以接受

所以本题思路大致如下:   读入数据。选取随机坐标。进入while循环,当受力不平衡时更新坐标,平衡则跳出,输出,结束。

判断受力是否平衡的函数思路如下:  把x,y方向的损失值赋值为0。访问所有孔的坐标,对受力情况进行正交分解,加到对应方向的损失值上。若两个损失值都为零返回true,否则返回false

我以vector储存孔的数据及对应重量。在此,因为double类型的精度问题,引入常量eps = 1e-4代替零。注意,损失值有正有负,故判断的应是(LossX < eps && LossX > -eps && LossY < eps && LossY > -eps), 切记记得判断-eps,否则损失值为0了也无法跳出循环。不要问我是怎么知道的

蒟蒻代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 

typedef std::pair point_int;
typedef std::pair point_db;
const double Eta = 1e-5, eps = 1e-4;
int N = 0;
std::vector vec;
std::vector vec_w;
double LossX = 0, LossY = 0;

void init(void);
void solve(void);
int read(void);
bool balanced(const point_db&);
bool equals_zero(double);

int main() {
    init();
    solve();
    return 0;
}

void init(void) {
    N = read();
    for (int i=0; i -eps && LossY < eps && LossY > -eps);
}

你可能感兴趣的:(OI)