1 条题解

  • 0

    题意分析:

    这道题目要求我们从给定的 m 个 n 维向量中选择 n 个线性无关的向量,使得它们的总价格最小。如果存在多个解,选择字典序最小的那个。解决这个问题的关键在于如何高效地维护一组线性无关的向量基,并在保证线性无关的前提下选择价格最低的向量。

    解题思路:

    向量表示与处理:

    使用高斯消元法来维护当前的基向量。基向量的每个维度需要逐步处理,确保新加入的向量与现有基线性无关。

    贪心选择:

    将向量按价格从小到大排序,如果价格相同,则选择编号较小的向量以保证字典序最小。然后依次尝试将每个向量加入基中,如果能成功加入(即该向量与当前基线性无关),则将其加入基并累加价格。

    结果输出:

    如果最终基的大小等于 n,则输出总价格和所选向量的编号;否则输出 0。

    实现步骤

    输入处理:读取向量数量 m 和维度 n,然后读取每个向量的坐标和价格。

    排序处理:将向量按价格升序排序,价格相同的按编号升序排序,以确保字典序最小。

    高斯消元维护基:遍历排序后的向量,尝试将其加入基中。使用高斯消元法检查当前向量是否能与现有基线性无关。如果可以,则加入基并记录价格和编号。

    结果输出:如果基的大小等于 n,输出总价格和所选向量编号(按升序排列);否则输出 0。

    代码实现

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <cmath>
    
    using namespace std;
    
    const double EPS = 1e-9;
    
    struct Vector {
        vector<int> coords;
        int price;
        int index;
    };
    
    bool compareByPriceAndIndex(const Vector& a, const Vector& b) {
        if (a.price != b.price) {
            return a.price < b.price;
        } else {
            return a.index < b.index;
        }
    }
    
    int rankOfMatrix(vector<vector<double>>& matrix, int n, int m) {
        int rank = 0;
        vector<bool> row_selected(m, false);
        for (int col = 0; col < n; ++col) {
            int pivot = -1;
            for (int row = 0; row < m; ++row) {
                if (!row_selected[row] && abs(matrix[row][col]) > EPS) {
                    pivot = row;
                    break;
                }
            }
            if (pivot == -1) continue;
            row_selected[pivot] = true;
            rank++;
            for (int row = 0; row < m; ++row) {
                if (row != pivot && abs(matrix[row][col]) > EPS) {
                    double mult = matrix[row][col] / matrix[pivot][col];
                    for (int c = col; c < n; ++c) {
                        matrix[row][c] -= mult * matrix[pivot][c];
                    }
                }
            }
        }
        return rank;
    }
    
    int main() {
        int m, n;
        cin >> m >> n;
        vector<Vector> vectors(m);
        for (int i = 0; i < m; ++i) {
            vectors[i].coords.resize(n);
            for (int j = 0; j < n; ++j) {
                cin >> vectors[i].coords[j];
            }
            vectors[i].index = i + 1;
        }
        for (int i = 0; i < m; ++i) {
            cin >> vectors[i].price;
        }
    
        sort(vectors.begin(), vectors.end(), compareByPriceAndIndex);
    
        vector<vector<double>> basis(n, vector<double>(n, 0));
        vector<int> basis_indices;
        int total_cost = 0;
    
        for (const auto& vec : vectors) {
            vector<double> current_vec(n);
            for (int i = 0; i < n; ++i) {
                current_vec[i] = vec.coords[i];
            }
    
            for (int i = 0; i < n; ++i) {
                if (abs(current_vec[i]) > EPS) {
                    if (abs(basis[i][i]) < EPS) {
                        basis[i] = current_vec;
                        basis_indices.push_back(vec.index);
                        total_cost += vec.price;
                        break;
                    } else {
                        double factor = current_vec[i] / basis[i][i];
                        for (int j = i; j < n; ++j) {
                            current_vec[j] -= factor * basis[i][j];
                        }
                    }
                }
            }
            if (basis_indices.size() == n) {
                break;
            }
        }
    
        if (basis_indices.size() == n) {
            sort(basis_indices.begin(), basis_indices.end());
            cout << total_cost << endl;
            for (int idx : basis_indices) {
                cout << idx << endl;
            }
        } else {
            cout << 0 << endl;
        }
    
        return 0;
    }
    
    • 1