1. 程式人生 > >bzoj4004: [JLOI2015]裝備購買高斯消元

bzoj4004: [JLOI2015]裝備購買高斯消元

bzoj4004: [JLOI2015]裝備購買

Description

臉哥最近在玩一款神奇的遊戲,這個遊戲裡有 n 件裝備,每件裝備有 m 個屬性,用向量zi(aj ,…,am) 表示
(1 <= i <= n; 1 <= j <= m),每個裝備需要花費 ci,現在臉哥想買一些裝備,但是臉哥很窮,所以總是盤算著
怎樣才能花盡量少的錢買儘量多的裝備。對於臉哥來說,如果一件裝備的屬效能用購買的其他裝備組合出(也就是
說臉哥可以利用手上的這些裝備組合出這件裝備的效果),那麼這件裝備就沒有買的必要了。嚴格的定義是,如果
臉哥買了 zi1,…zip這 p 件裝備,那麼對於任意待決定的 zh,不存在 b1,…,bp 使得 b1zi1 + … + bpzi
p = 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

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

Sample Input

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

Sample Output

2 2

HINT

如題目中描述,選擇裝備 1 裝備 2,裝備 1 裝備 3,裝備 2 裝備 3 均可,但選擇裝備 1 和裝備 2 的花費最小,為 2。對於 100% 的資料, 1 <= n;m <= 500; 0 <= aj <= 1000。
新加資料三組–2016.5.13

分析

把所有裝備看成向量,這樣的話就是求形成的裝備矩陣的秩就是可以選的最多的裝備數。
對於第二問,貪心第把小的裝備拿去消元即可。

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<cmath>
using namespace std;
const int N = 501000;
const
long double eps = 1e-5; struct data { long double a[510]; int v; bool operator < (const data &a) const {return v < a.v;} }a[510]; int ans1, ans2, n, m, b[510]; int main() { ios::sync_with_stdio(0); cin>>n>>m; for(int i = 1;i <= n; ++i) for(int j = 1;j <= m; ++j) cin>>a[i].a[j]; for(int i = 1;i <= n; ++i) cin>>a[i].v; sort(a + 1, a + n + 1); for(int i = 1;i <= n; ++i) for(int j = 1;j <= m; ++j) if(fabs(a[i].a[j]) > eps) { if(!b[j]) { b[j] = i; ++ans1; ans2 += a[i].v; break; } else { long double x = a[i].a[j] / a[b[j]].a[j]; for(int k = j;k <= m; ++k) a[i].a[k] -= x * a[b[j]].a[k]; } } cout<<ans1<<" "<<ans2<<endl; return 0; }