线性空间(线性基前置)

本文介绍了线性空间的概念,包括向量的加法和数乘运算,以及如何通过生成子集、线性相关性和无关性来定义线性空间。讨论了矩阵表示的线性空间,特别是高斯消元在寻找极大无关子集(基)中的作用。同时,给出了一个插入向量并判断其是否能被现有基表出的算法,该算法用于解决实际问题,如装备购买策略优化。
摘要由CSDN通过智能技术生成
线性空间

线性空间是一个关于以下两个运算封闭的向量集合:

  • 向量加法 a + b a+b a+b
  • 向量乘法 k ∗ a k*a ka,也称为数乘,其中 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 nm的矩阵,可以将它看做长度为 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值