引自强大而免费的微信小程序:皆我工具箱。
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
int main() {
int m, k;
cin >> m >> k;
vector<double> val(k);
vector<int> col_idx(k);
vector<int> row_idx(m+1, 0);
for (int i = 0; i < k; i++) {
int row, col;
double value;
cin >> row >> col >> value;
val[i] = value;
col_idx[i] = col;
row_idx[row+1]++;
}
for (int i = 1; i < m+1; i++) {
row_idx[i] += row_idx[i-1];
}
vector<double> x(m, 0);
vector<double> b(m);
for (int i = 0; i < m; i++) {
cin >> b[i];
}
vector<double> result(m, 0);
double error = 1e6;
while (error > 0.1) {
for (int i = 0; i < m; i++) {
result[i] = b[i];
for (int j = row_idx[i]; j < row_idx[i+1]; j++) {
if (i != col_idx[j]) {
result[i] -= val[j] * x[col_idx[j]];
}
}
result[i] /= val[row_idx[i]];
}
error = 0;
for (int i = 0; i < m; i++) {
error += pow(result[i] - x[i], 2);
x[i] = result[i];
}
error = sqrt(error);
}
for (int i = 0; i < m; i++) {
cout.precision(10);
cout << x[i] << endl;
}
return 0;
}
运行时报错IndexError:
原因是线性回归中,稀疏矩阵的行标应从1开始,并且记录的非零元素个数应为m+1而非m。
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
int main() {
int m, k;
cin >> m >> k;
vector<double> val(k);
vector<int> col_idx(k);
vector<int> row_idx(m+1, 0);
for (int i = 0; i < k; i++) {
int row, col;
double value;
cin >> row >> col >> value;
val[i] = value;
col_idx[i] = col;
row_idx[row+1]++;
}
for (int i = 1; i < m+1; i++) {
row_idx[i] += row_idx[i-1];
}
vector<double> x(m, 0);
vector<double> b(m);
for (int i = 0; i < m; i++) {
cin >> b[i];
}
vector<double> result(m, 0);
double error = 1e6;
while (error > 0.1) {
for (int i = 0; i < m; i++) {
result[i] = b[i];
for (int j = row_idx[i]; j < row_idx[i+1]; j++) {
if (i != col_idx[j]) {
result[i] -= val[j] * x[col_idx[j]];
}
}
result[i] /= val[row_idx[i]];
}
error = 0;
for (int i = 0; i < m; i++) {
error += pow(result[i] - x[i], 2);
x[i] = result[i];
}
error = sqrt(error);
}
for (int i = 0; i < m; i++) {
cout.precision(10);
cout << x[i] << endl;
}
return 0;
}
优化:
在计算过程中,可以避免每次迭代都重新计算非零元素对应的xi的值。
具体做法是在每次迭代开始之前,保存下上一次迭代的结果存储在last_result中。然后,在计算xi的新值时,即可直接使用上一次迭代的结果,而不需要从头开始计算。
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
int main() {
int m, k;
cin >> m >> k;
vector<double> val(k);
vector<int> col_idx(k);
vector<int> row_idx(m+1, 0);
for (int i = 0; i < k; i++) {
int row, col;
double value;
cin >> row >> col >> value;
val[i] = value;
col_idx[i] = col;
row_idx[row+1]++;
}
for (int i = 1; i < m+1; i++) {
row_idx[i] += row_idx[i-1];
}
vector<double> x(m, 0);
vector<double> b(m);
for (int i = 0; i < m; i++) {
cin >> b[i];
}
vector<double> result(m, 0);
double error = 1e6;
vector<double> last_result(m, 0); // 上一次迭代的结果
while (error > 0.1) {
for (int i = 0; i < m; i++) {
result[i] = b[i];
for (int j = row_idx[i]; j < row_idx[i+1]; j++) {
if (i != col_idx[j]) {
result[i] -= val[j] * x[col_idx[j]];
}
}
result[i] /= val[row_idx[i]];
}
error = 0;
for (int i = 0; i < m; i++) {
error += pow(result[i] - x[i], 2);
x[i] = result[i];
}
error = sqrt(error);
last_result = result; // 保存本次迭代的结果
}
for (int i = 0; i < m; i++) {
cout.precision(10);
cout << x[i] << endl;
}
return 0;
}