• 【数学 线性基】AcWing 209. 装备购买


    传送门:
    https://www.acwing.com/problem/content/description/211/

    分析

    采取这样的贪心策略:将物品看作是矩阵中的,按照花费升序排序,然后从 \(1-n\)​​ 扫描,当第 \(i\)​​ 个和前面加入的所有线性无关的时候,就将其花费计入答案,反之不计入。

    这样做为什么是对的呢?采用归纳法来证明:

    下证:前 \(n\)​​ 行采取上述策略能够在保证选出的行构成的线性空间与前 \(n\)​ 行构成的线性空间相等的前提下花费最小。

    • \(1\) 行,我们肯定需要将第一行加入贡献,满足。
    • 假设前 \(k\) 行满足上述贪心策略。
    • 下只需证明前 \(k+1\) 行采取上述贪心策略是最优的。
      • 如果前 \(k\) 行构成的线性空间和前 \(k+1\) 行构成的线性空间相等(也就是第 \(k+1\)​​ 能被前 \(k\)​ 行选出的线性表出),那么我们肯定不选取,满足最优。
      • 如果不相等,也就是第 \(k+1\)​ 行与前 \(k\)​ 行线性无关。假设我们不选取第 \(k+1\)​ 行,那么无论如何从前 \(k\)​ 行进行选取也不能使得选出的行构成的线性空间与前 \(k+1\)​​​ 行构成的线性空间相等,因此必须选。

    实现

    #include<bits/stdc++.h>
    using namespace std;
    
    #define debug(x) cerr << #x << ": " << (x) << endl
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define dwn(i,a,b) for(int i=(a);i>=(b);i--)
    #define pb push_back
    #define all(x) (x).begin(), (x).end()
    
    using ll = long long;
    
    inline void read(int &x){
        int s=0; x=1;
        char ch=getchar();
        while(ch<'0' || ch>'9') {if(ch=='-')x=-1;ch=getchar();}
        while(ch>='0' && ch<='9') s=(s<<3)+(s<<1)+ch-'0',ch=getchar();
        x*=s;
    }
    
    const int N=550;
    const double eps=1e-5;
    
    int n, m;
    int w[N][N], c[N];
    int idx[N];
    
    bool zero(double x){
    	return abs(x)<eps;
    }
    
    bool zero(vector<double> a){
    	for(auto i: a) if(!zero(i)) return false;
    	return true;
    }
    
    void change(vector<double> &a, vector<double> &b){
    	rep(i,0,m-1){
    		if(zero(a[i]) && !zero(b[i])) return;
    		if(!zero(a[i]) && zero(b[i])){
    			swap(a, b);
    			return;
    		}
    		if(!zero(a[i]) && !zero(b[i])){
    			double rate=a[i]/b[i];
    			rep(j,i,m-1) a[j]-=rate*b[j];
    			return;
    		}
    	}
    }
    
    int main(){
    	cin>>n>>m;
    	rep(i,1,n) rep(j,1,m) read(w[i][j]);
    	rep(i,1,n) read(c[i]);
    	rep(i,1,n) idx[i]=i;
    	sort(idx+1, idx+1+n, [](int x, int y){
    		return c[x]<c[y];
    	});
    	
    	vector<vector<double>> a;
    	ll res=0;
    	rep(i,1,n){
    		int p=idx[i];
    		vector<double> row;
    		rep(j,1,m) row.pb(w[p][j]);
    		
    		for(auto &vec: a) change(row, vec);
    		if(!zero(row)) a.pb(row), res+=c[p];
    	}
    	
    	cout<<a.size()<<' '<<res<<endl;
    	
    	return 0;
    
    
  • 相关阅读:
    AngularJS中实现无限级联动菜单
    理解AngularJS生命周期:利用ng-repeat动态解析自定义directive
    denounce函数:Javascript中如何应对高频触发事件
    Javascript中的循环变量声明,到底应该放在哪儿?
    优雅的数组降维——Javascript中apply方法的妙用
    如何利⽤360Quake挖掘某授权⼚商边缘站点漏洞
    Java课程设计--网络聊天室
    DS博客作业08--课程总结
    DS博客作业07--查找
    DS博客作业06--图
  • 原文地址:https://www.cnblogs.com/Tenshi/p/15863124.html
Copyright © 2020-2023  润新知