1. 程式人生 > >[JLOI2015]裝備購買,洛谷P3265,實數線性基

[JLOI2015]裝備購買,洛谷P3265,實數線性基

正題

      題目連結

      回想線性基的過程,是不是碰到第i位有數,就必須把第i位清空?

      其實這個就是一個高斯消元的過程,只不過他少了未知數。

      這題當然也可以用高斯消元做,看一下當前這個能不能被前面的構造出來,這樣的複雜度會顯得很高。

      思考運用線性基的性質。

      第i位為1。第i個數下面的數的第i位肯定為0.

      那麼現線上性基存的就是一個向量,每次遇到第x位不為0,而且線性基中這裡有向量,那就把向量減去線性基中的向量乘上一個數。(初等變換)

      然後如果沒有向量就存進去。

      到最後如果可以被線性基中的向量組合出來,那麼這個裝備(向量)就沒必要買。

      從小到大放,不能放的就丟掉,得到的一定是最小的數,而且可以證明取的裝備一定是最大的(別問我,要問我的感性

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

struct node{
	double a[510];
	int d;
	bool operator<(const node x)const{
		return d<x.d;
	}
}s[510];
int n,m;
double p[510][510];
bool tf[510];
double eps=1e-5;

bool insert(node x){
	bool we=false;
	for(int i=m;i>=1;i--)
		if(fabs(x.a[i])>eps){
			if(tf[i]) for(int j=1;j<=i;j++) x.a[j]-=p[i][j]*x.a[i]/p[i][i];
			else{
				for(int j=i;j>=1;j--) p[i][j]=x.a[j];
				we=true;tf[i]=true;
				break;
			}
		}
	return we;
}

int main(){
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++)
		for(int j=m;j>=1;j--)
			scanf("%lf",&s[i].a[j]);
	for(int i=1;i<=n;i++) scanf("%d",&s[i].d);
	sort(s+1,s+1+n);
	int ans=0,t=0;
	for(int i=1;i<=n;i++) if(insert(s[i])) ans+=s[i].d,t++;
	printf("%d %d\n",t,ans);
}