[BZOJ4004][JLOI2015]装备购买
题意
给你\(n\)个\(m\)维向量,每个向量有一个权值,求最小权极大线性无关组。
sol
按照权值排序从小到大插入就好了。
这样很好证明:若存在一组向量线性相关,那么肯定是删掉权值最大的那个向量最优。那么按权值从小到大插入时只要发现当前待插入向量与原向量集线性相关就不插入。
怎么维护向量集?类似线性基的方法维护即可。
此题精度比较卡,以下代码开\(long\ double\),\(eps\)取\(10^{-6}\)。
code
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define ld long double
int gi()
{
int x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') w=0,ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
const int N = 505;
const ld eps = 1e-6;
struct node{
ld p[N];int val;
bool operator < (const node &b) const
{return val<b.val;}
}a[N];
int n,m,ele,ans;ld p[N][N];
int main()
{
n=gi();m=gi();
for (int i=1;i<=n;++i)
for (int j=1;j<=m;++j)
a[i].p[j]=gi();
for (int i=1;i<=n;++i) a[i].val=gi();
sort(a+1,a+n+1);
for (int t=1;t<=n;++t)
for (int i=1;i<=m;++i)
{
if (fabs(a[t].p[i])<eps) continue;
if (fabs(p[i][i])<eps)
{
for (int j=i;j<=n;++j) p[i][j]=a[t].p[j];
++ele;ans+=a[t].val;break;
}
for (int j=m;j>=i;--j)
a[t].p[j]-=p[i][j]*a[t].p[i]/p[i][i];
}
printf("%d %d\n",ele,ans);
return 0;
}