P3265 [JLOI2015]装备购买

写在前面

线性基的水题竟然是紫题,可怜我高中的向量基础网课漏听了几节,导致昨天看了一天都没看懂,淦

luogu只有(5)个题解,还能水一波估值

思路

(n)件装备看成(n)个长度为(m)的向量,根据题目意思,购买的向量线性无关的(如果线性相关就不会去购买了),题目要求我们求出该线性空间的基

可以把(a_{i,j})看成系数矩阵,每个装备(z_i)即为一个行向量,用高斯消元求出行秩就是最少购买的装备数量

最少花的钱可以用贪心来求解:

对于每一个主元(x_i),在前(i-1)列为(0),第(i) 列不为(0)的行向量中,选出价格最低的去消元

证明应该不用写了

设花钱最少的基为(z[i_1],z[i_2],……z[i_p])该基内不包含价格最低的行向量(z[k])

因为极大线性不相关子集,所以(z[k])一定可以被上述基表出

可设:(z[k]=b_1z[i_1]+b_2z[i_2]+……b_pz[i_p])

化简得:(z[i_p]=(z[k]-b_1z[i_1]-……b_{p-1}z[i_{p-1}])/b_p)

显然(z[i_p])能被上面的基表出,即上述基与一开始设出的基相同,但是上述基总价格更小

证毕

#include<bits/stdc++.h>
using namespace std;
const int N=520;//淦 
long double a[N][N],eps=1e-8;
int n,m,w[N];
int dim,ans;
int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	cin>>n>>m;
	for(int i=1;i<=n;++i){
		for(int j=1;j<=m;++j){
			double x;
			scanf("%lf",&x);
			a[i][j]=x;
		}
	}
	for(int i=1;i<=n;++i)
	{
		int val;
		scanf("%d",&val);
		w[i]=val;
	}
	for(int i=1;i<=m;++i)
	{
		int now=0;
		for(int j=dim+1;j<=n;++j)
			if(fabs(a[j][i])>eps&&(now==0||w[j]<w[now])) 
				now=j;
		if(now==0) continue;
		++dim;ans+=w[now];
		for(int j=1;j<=m;++j) swap(a[now][j],a[dim][j]);
		swap(w[now],w[dim]);
		for(int j=1;j<=n;++j) 
		{
			if(dim!=j&&fabs(a[j][i])>eps)
			{
				long double rate=a[j][i]/a[dim][i];
				for(int k=i;k<=m;++k) a[j][k]-=rate*a[dim][k];	
			} 
		}
	}
	cout<<dim<<" "<<ans;
	return 0;
}


原文地址:https://www.cnblogs.com/pyyyyyy/p/12732395.html