欢迎大家访问我的老师的OJ———caioj.cn
题面描述
思路
提要:
做此题时,请务必了解线性空间的基以及矩阵的秩。
把 n n n件装备看作 n n n个长度为 m m m的向量,
根据题意,购买的装备对应的向量应该是线性无关的(要满足向量不能被其他向量表出)。
要买下最多数量的装备,其实就是求线性空间的任意一个基的个数。
把 a i . j ( 1 ≤ i ≤ n , 1 ≤ j ≤ m ) a_{i.j}(1\le i\le n,1\le j\le m) ai.j(1≤i≤n,1≤j≤m)看作系数矩阵,每个装备 z i z_i zi都是一个行向量。
用高斯消元求出该矩阵的秩(相当于线性空间的基中元素个数),就得到了能买下的装备的最多数量。
本题还需要求花最少的钱。我们只需要在高斯消元的过程中,使用贪心策略,对于每一个主元 x i x_i xi,在前 i − 1 i-1 i−1列为 0 0 0、第 i i i列不为 0 0 0的行向量中,选择价格最低的一个,小区其他行中i列的值。
用反证法证明。假设花费价钱最少的基底(简称基) z [ i 1 ] , z [ i 2 ] , z [ i 3 ] , . . . . . . , z [ i p ] z[i_1],z[i_2],z[i_3],......,z[i_p] z[i1],z[i2],z[i3],......,z[ip]不包含价格最少的行向量 z [ k ] z[k] z[k],因为基底是极大线性无关子集,所以 z [ k ] z[k] z[k]能被 z [ i 1 ] , z [ i 2 ] , z [ i 3 ] , . . . . . . , z [ i p ] z[i_1],z[i_2],z[i_3],......,z[i_p] z[i1],z[i2],z[i3],......,z[ip]表出,不妨设 z [ k ] z[k] z[k]= b 1 z [ i 1 ] + b 2 z [ i 2 ] + b 3 z [ i 3 ] + . . . . . . + b p z [ i p ] b_1z[i_1]+b_2z[i_2]+b_3z[i_3]+......+b_pz[i_p] b1z[i1]+b2z[i2]+b3z[i3]+......+bpz[ip].
移向就有 z [ i p ] = ( z [ k ] − b 1 z [ i 1 ] − b 2 z [ i 2 ] − b 3 z [ i 3 ] − . . . . . . − b p − 1 z [ i p − 1 ] ) / b p z[i_p]=(z[k]-b_1z[i_1]-b_2z[i_2]-b_3z[i_3]-......-b_{p-1}z[i_{p-1}])/b_p z[ip]=(z[k]−b1z[i1]−b2z[i2]−b3z[i3]−......−bp−1z[ip−1])/bp,即 z [ i p ] z[i_p] z[ip]能被 z [ k ] z[k] z[k]与 z [ i 1 ] , z [ i 2 ] , z [ i 3 ] , . . . . . . , z [ i p − 1 ] z[i_1],z[i_2],z[i_3],......,z[i_{p-1}] z[i1],z[i2],z[i3],......,z[ip−1]表出。
所以这两个基都能表出相同的线性空间,而含有 z [ k ] z[k] z[k]明显总费用最低,与假设矛盾。
证毕。
AC code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#define eps 1e-6
using namespace std;
long double a[510][510];
int n,ans,m,dim,c[510];
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
double tmp;scanf("%lf",&tmp);a[i][j]=tmp;
}
for(int i=1;i<=n;i++)scanf("%d",&c[i]);
dim=0;ans=0;
for(int i=1;i<=m;i++)
{
int x=0;
for(int j=dim+1;j<=n;j++)
if(fabs(a[j][i])>eps&&(x==0||c[x]>c[j]))x=j;
if(x==0)continue;
ans+=c[x];dim++;
for(int j=dim;j<=m;j++)swap(a[dim][j],a[x][j]);
swap(c[x],c[dim]);
for(int k=dim+1;k<=n;k++)
{
if(fabs(a[k][i])>eps)
{
for(int j=m;j>=i;j--)a[k][j]-=a[k][i]/a[dim][i]*a[dim][j];
}
}
}
printf("%d %d\n",dim,ans);
return 0;
}