BZOJ4004--装备购买
装备购买
脸哥最近在玩一款神奇的游戏,这个游戏里有 \(n\) 件装备,每件装备有 \(m\) 个属性,用向量\(z[i]=(a_{i,1},a_{i,2},..,a_{i,m})\) 表示,每个装备需要花费 \(c_i\)。
现在脸哥想买一些装备,但是脸哥很穷,所以总是盘算着怎样才能花尽量少的钱买尽量多的装备。
对于脸哥来说,如果一件装备的属性能用购买的其他装备组合出(也就是说脸哥可以利用手上的这些装备组合出这件装备的效果),那么这件装备就没有买的必要了。
严格的定义是,如果脸哥买了 \(z[i_1],z[i_2],…,z[i_p]\) 这 p 件装备,并且不存在实数 \(b_1,b_2,…,b_p\) 使得 \(z[k]=b_1z[i_1]+b_2z[i_2]+…+b_pz[i_p]\),那么脸哥就会买 \(z[k]\),否则 \(z[k]\) 对脸哥就是无用的了,自然不必购买。
脸哥想要在买下最多数量的装备的情况下花最少的钱,你能帮他算一下吗?
输入格式
第一行包含两个整数 \(n\)和 \(m\)。
接下来 \(n\) 行,每行 \(m\) 个数,其中第 \(i\) 行描述装备 \(i\) 的各项属性值。
接下来一行 \(n\) 个数,其中第 \(i\) 个数表示购买第 \(i\) 件装备的花费 \(c_i\)。
输出格式
输出占一行,包含两个整数,第一个整数表示能够购买的最多装备数量,第二个整数表示在购买最多数量的装备的情况下的最小花费。
数据范围
\(1≤n,m≤500\),
\(0≤a_{i,j}≤1000\)
输入样例:
3 3
1 2 3
3 4 5
2 3 4
1 1 2
输出样例:
2 2
题解
一个 \(n*m\) 的矩阵,需要经过构造线性基,并不断往线性基里面添加元素,存在的话进行消除,不存在进行添加。
因为要保证最小,所以添加之前贪心一下进行操作,所谓贪心就是费用从小到大排序。
这个题比较卡精度~~
代码
#include <cmath>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 555;
int b[maxn];
const double eps = 1e-5;
struct node{
double a[maxn];
int n;
};
node a[maxn];
bool cmp(node x,node y){
return x.n<y.n;
}
void Base(int n,int m){
int ans=0,cnt=0;
sort(a,a+n,cmp);
for(int i=0;i<=500;++i)b[i]=-1;
for(int i=0;i<n;++i){
for(int j=0;j<m;++j){
if(fabs(a[i].a[j])<eps)continue;
if(b[j]!=-1){
double tmp=a[i].a[j]/a[b[j]].a[j];
for(int k=j;k<m;++k){
a[i].a[k]-=tmp*a[b[j]].a[k];
}
}
else{
b[j]=i;
cnt++;
ans+=a[i].n;
break;
}
}
}
printf("%d %d\n",cnt,ans);
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<n;++i)
for(int j=0;j<m;++j)
scanf("%lf",&a[i].a[j]);
for(int i=0;i<n;++i)
scanf("%d",&a[i].n);
Base(n,m);
return 0;
}
新赛季的开始