BZOJ4004:[JLOI2015]装备购买——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=4004
https://www.luogu.org/problemnew/show/P3265
脸哥最近在玩一款神奇的游戏,这个游戏里有 n 件装备,每件装备有 m 个属性,用向量zi(aj ,.....,am) 表示 (1 <= i <= n; 1 <= j <= m),每个装备需要花费 ci,现在脸哥想买一些装备,但是脸哥很穷,所以总是盘算着怎样才能花尽量少的钱买尽量多的装备。
对于脸哥来说,如果一件装备的属性能用购买的其他装备组合出(也就是说脸哥可以利用手上的这些装备组合出这件装备的效果),那么这件装备就没有买的必要了。严格的定义是,如果脸哥买了 zi1,.....zip这 p 件装备,那么对于任意待决定的 zh,不存在 b1,....,bp 使得 b1zi1 + ... + bpzip = zh(b 是实数),那么脸哥就会买 zh,否则 zh 对脸哥就是无用的了,自然不必购买。
举个例子,z1 =(1; 2; 3);z2 =(3; 4; 5);zh =(2; 3; 4),b1 =1/2,b2 =1/2,就有 b1z1 + b2z2 = zh,那么如果脸哥买了 z1 和 z2 就不会再买 zh 了。脸哥想要在买下最多数量的装备的情况下花最少的钱,你能帮他算一下吗?
题意显然不是人话,简单点说就是给一堆有费用的向量,求最小费用的基。
做完这道题对线性基有了更深刻的理解。
贪心做先按照费用排序再线性基往里填。
线性基教程推荐:https://blog.sengxian.com/algorithms/linear-basis的确很好。
当这位不存在时就将其填充上。
(事实上还需要和前后消一下不过本题不需要。)
当这位存在时与后面的高斯消元一下使该向量于这位为0。
PS:卡精度注意下。
#include<cstdio> #include<iostream> #include<cstring> #include<cmath> #include<cctype> #include<algorithm> using namespace std; typedef long double dl; const dl eps=1e-6; const int N=510; inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch=='-';ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } struct item{ dl x[N]; int c; }a[N]; int b[N]; inline bool cmp(item a,item b){ return a.c<b.c; } int main(){ int n=read(),m=read(); for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ a[i].x[j]=read(); } } for(int i=1;i<=n;i++)a[i].c=read(); sort(a+1,a+n+1,cmp); int cnt=0,ans=0; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ if(fabs(a[i].x[j])>eps){ if(b[j]){ dl t=a[i].x[j]/a[b[j]].x[j]; for(int k=j;k<=m;k++) a[i].x[k]-=a[b[j]].x[k]*t; }else{ b[j]=i; cnt++;ans+=a[i].c; break; } } } } printf("%d %d\n",cnt,ans); return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/ +
+++++++++++++++++++++++++++++++++++++++++++