「BZOJ4004」「JLOI2015」装备购买

题目描述

脸哥最近在玩一款神奇的游戏,这个游戏里有 n 件装备,每件装备有 m 个属性,用向量 zi(a1,,aj,,am) 表示 (1in;1jm) ,每个装备需要花费 ci ,现在脸哥想买一些装备,但是脸哥很穷,所以总是盘算着怎样才能花尽量少的钱买尽量多的装备。

对于脸哥来说,如果一件装备的属性能用购买的其他装备组合出(也就是说脸哥可以利用手上的这些装备组合出这件装备的效果),那么这件装备就没有买的必要了。严格的定义是,如果脸哥买了 z1,,zp p 件装备,那么对于任意待决定的 zh ,不存在 b1,,bp 使得 b1z1+...+bpzp=zh b 是实数),那么脸哥就会买 zh ,否则 zh 对脸哥就是无用的了,自然不必购买。

举个例子, z1=(1,2,3);z2=(3,4,5);zh=(2,3,4)b1=12b2=12 , 就有 b1z1+b2z2=zh ,那么如果脸哥买了 z1 z2 就不会再买 zh 了。脸哥想要在买下最多数量的装备的情况下花最少的钱,你能帮他算一下吗?

输入输出格式

输入格式:

第一行两个数 n,m 。接下来 n 行,每行 m 个数,其中第 i 行描述装备 i 的各项属性值。接下来一行 n 个数,其中 ci 表示购买第 i 件装备的花费。

输出格式:

一行两个数,第一个数表示能够购买的最多装备数量,第二个数表示在购买最多数量的装备的情况下的最小花费

输入输出样例

输入样例#1:

3 3
1 2 3
3 4 5
2 3 4
1 1 2

输出样例#1:

2 2

说明

如题目中描述,选择装备 1 装备 2 ,装备 1 装备 3 ,装备 2 装备 3 均可,但选择装备 1 和装备 2 的花费最小,为 2

对于 100% 的数据, 1n,m500 ,0aj1000

题解

题意:给定 n m 维向量,求一个最大线性无关组,并且最大线性无关组中的向量权值和最小。
首先我们不考虑权值的问题。
求一个 m 维最大线性无关向量组,可以根据 《工程数学-线性代数》上介绍的方法,将向量加入矩阵,然后进行初等行变换将其化为行阶梯型矩阵。

举个栗子(样例):

132243354r32r1r23r1100221342r2×1/2100211322r3+r2100210320

其中最终的行阶梯型矩阵的秩 R(B)=2 ,所以原向量组的最大线性无关组的大小为 2
接下来我们在来考虑权值的问题。由于矩阵进行初等行变换秩不变,我们可以贪心得从小到大加入矩阵,然后尽量用权值低的向量消掉权值高的向量即可。
在这里我用的类似线性基维护。
复杂度 O(nlog2n+nm2)

My Code

本题卡精度,所以使用 long double,并开大eps
否则你会这样:
这里写图片描述
这里写图片描述

/**************************************************************
    Problem: 4004
    User: infinityedge
    Language: C++
    Result: Accepted
    Time:1372 ms
    Memory:7908 kb
****************************************************************/

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>

#define eps 1e-6

using namespace std;

struct vec{
    long double d[501];
    int c;
}v[505];

int cmp(vec x, vec y){
    return x.c < y.c;
}

long double b[501][501];
int n, m;
int ans[501], vis[501];
void solve(){
    for(int i = 1; i <= n; i ++){
        for(int j = m; j >= 1; j --){
            if(fabs(v[i].d[j]) > eps){
                if(fabs(b[j][j]) > eps){
                    long double dk = v[i].d[j] / b[j][j];
                    for(int k = 1; k <= m; k ++){
                        v[i].d[k] -= b[j][k] * dk;
                    }
                }else{
                    for(int k = 1; k <= m; k ++){
                        b[j][k] = v[i].d[k];
                    }
                    ans[j] = v[i].c;
                    vis[j] = 1;
                    break;
                }   
            }
        }
    }
}

int main(){
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i ++){
        for(int j = 1; j <= m; j ++){
            scanf("%Lf", &v[i].d[j]);
        }
    }
    for(int i = 1; i <= n; i ++){
        scanf("%d", &v[i].c);
    }
    sort(v + 1, v + n + 1, cmp);
    solve();
    int pans = 0, cnt = 0;
    for(int i = 1; i <= m; i ++){
        if(vis[i]) cnt++, pans += ans[i];
    }
    printf("%d %d\n", cnt, pans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/infinity_edge/article/details/78725487