1. 程式人生 > 實用技巧 >《演算法競賽進階指南》0x35高斯消元與線性空間 裝備購買

《演算法競賽進階指南》0x35高斯消元與線性空間 裝備購買

題目連結:https://www.acwing.com/problem/content/211/

求矩陣的最大無關組的維數,也就是行向量的極大無關組,線性空間的一組基(因為線性空間的一組基可以表示線性空間中的其他任意的向量,他們之間不能相互表示),可以用高斯消元的方式,求維數,但是本題不僅僅要求得出維數,還得得出在這樣的維數的情況下最小的花費,所以需要利用貪心的方法,掃描到第i個變數時,需要檢查所有的含這個變數的最小的花費,可以證明,在不選這個花費的情況下情況不會變的更優(反證法證明)。中間可能會出現一些自由元,所以我們需要記錄當前的非自由元構成的dimention。

還有一個問題就是,需要使用long double 防止除法溢位,longdouble大約支援1.2*10^-400~1.2*10^400之間的小數。這是一個重點。

程式碼:

#include<iostream>
#include<cstdio>
#include<math.h>
using namespace std;
#define maxn 510
const double eps=1e-8;
long double a[maxn][maxn];
int c[maxn];
int n,m;
int main(){
    double tmp;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf(
"%lf",&tmp); a[i][j]=tmp; } } int ans=0; for(int i=1;i<=n;i++){ scanf("%lf",&tmp); c[i]=tmp; } int dim=0;//表示矩陣的維數 //對每個未知量進行一次消元,所以i的範圍是到m for(int i=1;i<=m;i++){ int now=-1; for(int j=dim+1;j<=n;j++){//找出當前位置的最小的花費
if(fabs(a[j][i])>eps && (now==-1 || c[j]<c[now])){ now=j; } } if(now==-1)continue;//當前主元是自由元 dim++;//n個行向量對應的特徵空間的維數增加 ans+=c[now]; for(int j=1;j<=m;j++) swap(a[now][j],a[dim][j]); swap(c[now],c[dim]); for(int j=1;j<=n;j++){//掃描所有除了當前行之外的行 if(j!=dim && fabs(a[j][i])>eps){ long double rate=a[j][i]/a[dim][i]; for(int k=i;k<=m;k++) a[j][k]-=a[dim][k]*rate;//第j行減去第dim行的rate倍 } } } cout<<dim<<" "<<ans<<endl; }