题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4004
看Zinn博客水过去……
运用拟阵可以证明按价格从小到大买的贪心是正确的。但自己还不会。
然后如果当前物品可以被线性表出就不买了。否则买,在第一个不能线性表出的位置上记录这个物品,表示按已经被消成这样的这个物品的这一位来消掉这一位是可以和前面那些位的消的情况吻合的。
然后因为卡精度而用long double。在printf里是Lf。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define ld long double using namespace std; const int N=505;const ld eps=1e-8; int n,m,ans,cnt,p[N]; bool vis[N]; struct Node{ ld a[N];int w; }t[N]; bool cmp(Node u,Node v){return u.w<v.w;} int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)scanf("%Lf",&t[i].a[j]); for(int i=1;i<=n;i++)scanf("%d",&t[i].w); sort(t+1,t+n+1,cmp); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if(fabs(t[i].a[j])<eps)continue; if(!vis[j]) { vis[j]=1;p[j]=i; ans+=t[i].w;cnt++;break; } else { ld tmp=t[i].a[j]/t[p[j]].a[j]; for(int k=j;k<=m;k++) t[i].a[k]-=t[p[j]].a[k]*tmp; } } printf("%d %d\n",cnt,ans); return 0; }