线性空间
线性空间是一个关于以下两个运算封闭的向量集合:
- 向量加法 a + b a+b a+b。
- 向量乘法 k ∗ a k*a k∗a,也称为数乘,其中 k k k是标量。
生成子集
给定若干个向量集合 A = { a 1 , a 2 , . . , a n } A= \{a_1,a_2,..,a_n\} A={a1,a2,..,an},若向量 b b b能由集合 A A A经过向量加法和数乘表示出来,称 b b b能被 A A A表出。 A A A构成的所有向量构成一个线性空间, A A A称为这个线性空间的生成子集。
线性相关/无关
任意选出线性空间的若干个向量,若其中存在一个向量能被其他向量表出,则称这些向量线性相关,否则称为线性无关。
基
线性无关的生成子集称为线性空间的基底,简称为基,也就是线性空间的极大生成子集。
矩阵意义下的线性空间
对于一个 n ∗ m n*m n∗m的矩阵,可以将它看做长度为 m m m的向量,那么这 n n n个行向量能表出的所有行向量构成了一个线性空间。对这个矩阵进行高斯消元得到行最简矩阵(对角矩阵),显然这个行最简矩阵所有非零行线性无关。因为高斯消元本身就是在做向量加法和数乘,因此不改变行向量表出的线性空间,于是行最简矩阵的所有非零行向量就是该线性空间的一个极大无关子集 (基)。
向量的插入
若插入向量的前 i i i位为 0 0 0,那么直接跳过,否则如果第一个非零位置在之前的无关子集中不存在,那么直接插入;否则就应该将该向量的非零位置通过已经确定的向量消去,这个过程实际上也就是高斯消元的过程,只不过是一个个插入。
long double a[510][510];
bool insert(ld *x) {
for (int i = 1; i <= m; i++) {
if (fabs(x[i]) < eps) continue;
if (fabs(a[i][i]) < eps) {
for (int j = i; j <= m; j++) a[i][j] = x[j];
return 1;
}
long double k = x[i] / a[i][i];
for (int j = i; j <= m; j++) x[j] -= k * a[i][j];
}
return 0;
}
洛谷P3265 [JLOI2015]装备购买
//
// Created by Happig on 2021/3/5.
//
#include <bits/stdc++.h>
#include <unordered_map>
using namespace std;
#define ENDL "\n"
#define lowbit(x) (x & (-x))
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<double, double> pdd;
const double eps = 1e-8;
const double pi = acos(-1.0);
const int inf = 0x3f3f3f3f;
const double dinf = 1e300;
const ll INF = 1e18;
const int Mod = 1e9 + 7;
const int maxn = 2e5 + 10;
int n, m, ans, cnt;
ld b[510][510];
struct node {
int w;
ld a[510];
bool operator<(const node &p) const {
return w < p.w;
}
} c[510];
//直接消元也是正确的
//void guass() {
// for (int i = 1; i <= n; i++) {
// int temp = i;
// for (int j = i + 1; j <= n; j++)
// if (fabs(a[j][i]) >= eps && w[j] < w[temp]) {
// temp = j;
// }
// if (fabs(a[temp][i]) < eps) continue;
// if (temp != i) {
// for (int j = 1; j <= m; j++) swap(a[i][j], a[temp][j]);
// swap(w[i], w[temp]);
// }
// ans += w[i], cnt++;
// for (int j = m; j >= i; j--) a[i][j] /= a[i][i];
// for (int j = i + 1; j <= n; j++) {
// for (int k = m; k >= i; k--) {
// a[j][k] -= a[j][i] * a[i][k];
// }
// }
// for (int j = i + 1; j <= m; j++) {
// for (int k = n; k >= i; k--) {
// a[k][j] -= a[i][j] * a[k][i];
// }
// }
// }
//}
bool insert(ld *x) {
for (int i = 1; i <= m; i++) {
if (fabs(x[i]) < eps) continue;
if (fabs(b[i][i]) < eps) {
for (int j = i; j <= m; j++) b[i][j] = x[j];
return 1;
}
ld k = x[i] / b[i][i];
for (int j = i; j <= m; j++) x[j] -= k * b[i][j];
}
return 0;
}
int main() {
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
//ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
scanf("%Lf", &c[i].a[j]);
for (int i = 1; i <= n; i++) scanf("%d", &c[i].w);
// guass();
sort(c + 1, c + 1 + n);
for (int i = 1; i <= n; i++) {
if (insert(c[i].a)) {
cnt++;
ans += c[i].w;
}
}
printf("%d %d\n", cnt, ans);
return 0;
}