题目描述详见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 <iostream>
#include <utility>
#include <vector>
#include <cmath>
#include <cstdlib>
#include <cstdio>
#include <ctime>
typedef std::pair<int, int> point_int;
typedef std::pair<double, double> point_db;
const double Eta = 1e-5, eps = 1e-4;
int N = 0;
std::vector<point_int> vec;
std::vector<int> 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<N; i++) {
int x = read(), y = read(), w = read();
vec.push_back(point_int(x, y));
vec_w.push_back(w);
}
return;
}
void solve(void) {
double x0 = double(rand())/double(RAND_MAX),
y0 = double(rand())/double(RAND_MAX);
point_db p = point_db(x0, y0);
bool done = balanced(p);
while (!done) {
p.first -= (LossX*Eta);
p.second -= (LossY*Eta);
done = balanced(p);
}
printf("%.3f %.3f\n", p.first, p.second);
}
int read(void) {
char ch = getchar();
int res = 0, x = 1;
while (!isdigit(ch)) {
if (ch == '-')
x = -1;
ch = getchar();
}
while (isdigit(ch)) {
res = res*10 + ch-'0';
ch = getchar();
}
return res*x;
}
bool balanced(const point_db& pos) {
LossX = LossY = 0.0;
for (int i=0; i<N; i++) {
double lx = pos.first-vec[i].first, ly = pos.second-vec[i].second;
double lc = sqrt(lx*lx + ly*ly);
double sinx = ly/lc, cosx = lx/lc;
LossY += (vec_w[i]*sinx);
LossX += (vec_w[i]*cosx);
}
return (LossX < eps && LossX > -eps && LossY < eps && LossY > -eps);
}