209. 装备购买

题目链接

209. 装备购买

脸哥最近在玩一款神奇的游戏,这个游戏里有 n 件装备,每件装备有 m 个属性,用向量 z[i]=(ai,1,ai,2,..,ai,m) 表示,每个装备需要花费 ci

现在脸哥想买一些装备,但是脸哥很穷,所以总是盘算着怎样才能花尽量少的钱买尽量多的装备。

对于脸哥来说,如果一件装备的属性能用购买的其他装备组合出(也就是说脸哥可以利用手上的这些装备组合出这件装备的效果),那么这件装备就没有买的必要了。

严格的定义是,如果脸哥买了 z[i1],z[i2],,z[ip]p 件装备,并且不存在实数 b1,b2,,bp 使得 z[k]=b1z[i1]+b2z[i2]++bpz[ip],那么脸哥就会买 z[k],否则 z[k] 对脸哥就是无用的了,自然不必购买。

脸哥想要在买下最多数量的装备的情况下花最少的钱,你能帮他算一下吗?

输入格式

第一行包含两个整数 nm

接下来 n 行,每行 m 个数,其中第 i 行描述装备 i 的各项属性值。

接下来一行 n 个数,其中第 i 个数表示购买第 i 件装备的花费 ci

输出格式

输出占一行,包含两个整数,第一个整数表示能够购买的最多装备数量,第二个整数表示在购买最多数量的装备的情况下的最小花费。

数据范围

1n,m500,
0ai,j1000

输入样例:

3 3 1 2 3 3 4 5 2 3 4 1 1 2

输出样例:

2 2

解题思路

线性基

显然题目要求找的线性基元素数量,即极大线性无关组的秩,可用高斯消元求解,关键在于求解的同时使代价最少
贪心策略:每次选择主元时选择满足要求的代价最少的那个
证明(来自蓝书):
该贪心策略可用反证法证明。假设花费价钱最少的基底是 z[i1],z[i2],,z[ip], 其 中不包含价格最低的行向量 z[k] 。因为基底是极大线性无关子集, 所以 z[k] 能被 z[i1],z[i2],,z[ip] 表出, 不妨设 z[k]=b1z[i1]+b2z[i2]++bpz[ip]
移项变换可得 z[ip]=(z[k]b1z[i1]bp1z[ip1])/bp, 即 z[ip] 能被 z[k]z[i1],z[i2],,z[ip1] 表出。故 z[k],z[i1],z[i2],,z[ip1] 能与 z[i1],z[i2],,z[ip] 表示相同的线性空间, 是一个总价格更低的基底, 与假设矛盾。

  • 时间复杂度:O(nm2)

代码

// Problem: 装备购买 // Contest: AcWing // URL: https://www.acwing.com/problem/content/211/ // Memory Limit: 64 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) // %%%Skyqwq #include <bits/stdc++.h> //#define int long long #define help {cin.tie(NULL); cout.tie(NULL);} #define pb push_back #define fi first #define se second #define mkp make_pair using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef pair<LL, LL> PLL; template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; } template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; } template <typename T> void inline read(T &x) { int f = 1; x = 0; char s = getchar(); while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); } while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar(); x *= f; } const int N=505; const long double eps=1e-8; int n,m,c[N],k,res; long double a[N][N]; int main() { help; cin>>n>>m; for(int i=0;i<n;i++) for(int j=0;j<m;j++)cin>>a[i][j]; for(int i=0;i<n;i++)cin>>c[i]; for(int i=0;i<m;i++) { int now=-1; for(int j=k;j<n;j++) if(fabs(a[j][i])>eps&&(now==-1||c[now]>c[j])) now=j; if(now==-1)continue; res+=c[now]; swap(a[k],a[now]); swap(c[k],c[now]); for(int j=0;j<n;j++) { if(j!=k&&fabs(a[j][i])>eps) { long double rate=a[j][i]/a[k][i]; for(int t=0;t<m;t++)a[j][t]-=rate*a[k][t]; } } k++; if(k==n)break; } cout<<k<<' '<<res; return 0; }

__EOF__

本文作者acwing_zyy
本文链接https://www.cnblogs.com/zyyun/p/16533988.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zyy2001  阅读(38)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示