1. 程式人生 > >【bzoj4004】【JLOI2015】裝備購買 (線性基+高斯消元)

【bzoj4004】【JLOI2015】裝備購買 (線性基+高斯消元)

complete truct algo turn insert input 否則 沒有 main

Description

臉哥最近在玩一款神奇的遊戲,這個遊戲裏有 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 了。臉哥想要在買下最多數量的裝備的情況下花最少的錢,你能幫他算一下嗎?

Input

第一行兩個數 n;m。接下來 n 行,每行 m 個數,其中第 i 行描述裝備 i 的各項屬性值。接下來一行 n 個數, 其中 ci 表示購買第 i 件裝備的花費。

Output

一行兩個數,第一個數表示能夠購買的最多裝備數量,第二個數表示在購買最多數量的裝備的情況下的最小花費

題解:

這乍一看,似乎沒有什麽規律,但是,仔細一想,這題跟線性基有點像。

普通的異或線性基是將十進制數轉為二進制,將 01 串作為向量,加入線性基,這道題將一個十進制的向量插入線性基。

我們可以用高斯消元消去最高位替代異或,如下:

1 bool insert(Vector x){
2     for(int i=m;i>=1
;i--){ 3 if(fabs(x.v[i])<eps)continue; 4 if(a[i].empty()){a[i]=x;return true;} 5 double k=x.v[i]/a[i].v[i]; 6 for(int j=1;j<=m;j++)x.v[j]-=a[i].v[j]*k; 7 if(x.empty())return false; 8 } 9 }

這同樣滿足線性基的性質,(感性理解)

COMPLETE CODE:

 1 #include<iostream>
 2
#include<cstdio> 3 #include<algorithm> 4 #include<cmath> 5 #include<cstring> 6 using namespace std; 7 8 #define eps 1e-5 9 int n,m,x,sum,ans; 10 struct Vector{ 11 double v[505]; 12 int c; 13 bool operator<(const Vector &b)const{ 14 return c<b.c; 15 } 16 bool empty(){ 17 for(int i=1;i<=m;i++) 18 if(fabs(v[i])>=eps)return false; 19 return true; 20 } 21 }a[505]; 22 struct LB{ 23 Vector a[505]; 24 bool insert(Vector x){ 25 for(int i=m;i>=1;i--){ 26 if(fabs(x.v[i])<eps)continue; 27 if(a[i].empty()){a[i]=x;return true;} 28 double k=x.v[i]/a[i].v[i]; 29 for(int j=1;j<=m;j++)x.v[j]-=a[i].v[j]*k; 30 if(x.empty())return false; 31 } 32 } 33 }lb; 34 35 int main(){ 36 scanf("%d%d",&n,&m); 37 for(int i=1;i<=n;i++) 38 for(int j=1;j<=m;j++)scanf("%d",&x),a[i].v[j]=x; 39 for(int i=1;i<=n;i++)scanf("%d",&a[i].c); 40 sort(a+1,a+n+1); 41 for(int i=1;i<=n;i++) 42 if(lb.insert(a[i]))sum++,ans+=a[i].c; 43 printf("%d %d",sum,ans); 44 }

註意!! 這題卡精度!!

【bzoj4004】【JLOI2015】裝備購買 (線性基+高斯消元)