BZOJ 4004 JLOI2015 装备购买 高斯消元+线性基

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4004

 

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

一行两个数,第一个数表示能够购买的最多装备数量,第二个数表示在购买最多数量的装备的情况下的最小花费。 

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.
 
 
——————————————————————————————————————————————————————
 
 

题意概述:

·给出N个M维向量,选择向量i花费代价ci。求一个包含向量最多的线性无关组,使得选择这个无关组的代价最小。

·N,M<=500,ai<=1000(话说ci呢?)

 

分析:

·可以把向量看成一个多元一次方程。如果一些方程相关,那么这些方程可以互相表示。

·考虑高斯消元过程,发现最终系数为0的方程能够被上面的一些方程表示出来,换言之不为0的向量一旦和这些向量相组合就不是线性无关,不符合要求。最终高斯消元剩下的非0的方程数量就是这个集合中的线性无关组数量。即一个向量集和的线性不相关向量数量是唯一确定的,并且和高斯消元后非0向量的数量相同。(可以YY两个线性相关向量集合在一起变成一个新集合的情况)

·解决了最大购买数的问题,那么最小代价?

·贪心,把所有的向量按照权值从小到大排序,然后直接消元,遇到当前向量关键维度的值为0的时候选择还没有考虑的向量中权值最小的那个作为现在的关键字,延后考虑当前向量。有了上面第一问的分析之后这个贪心显然是正确的。具体实现搞个链表什么的。

·最坑的地方还是精度......最后看精度没救了强行上了逆元来进行模意义下的运算,然而这好像就步入了玄学的领域......为了不冲突就只能在比较大的mo意义下搞事情然而有点慢啊......

 

 

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cstdlib>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<queue>
 8 #include<set>
 9 #include<map>
10 #include<vector>
11 #include<cctype>
12 using namespace std;
13 const int maxn=505;
14 const int mo=1000000007;
15 typedef long long LL;
16 
17 int N,M,C[maxn],next[maxn];
18 struct data{
19     int id,v;
20     friend bool operator < (data x,data y){
21         return x.v<y.v;
22     }
23 }D[maxn];
24 int A[maxn][maxn];
25 
26 void data_in()
27 {
28     scanf("%d%d",&N,&M);
29     int x;
30     for(int i=1;i<=N;i++)
31     for(int j=1;j<=M;j++)
32         scanf("%d",&A[i][j]);
33     for(int i=1;i<=N;i++) scanf("%d",&C[i]);
34 }
35 void exgcd(LL a,LL b,LL &d,LL &x,LL &y)
36 {
37     if(!b) d=a,x=1,y=0;
38     else exgcd(b,a%b,d,y,x),y-=(a/b)*x;
39 }
40 int inv(int a)
41 {
42     LL x=0,y=0,d=0; exgcd(a,mo,d,x,y);
43     return x;
44 }
45 int Gauss()
46 {
47     int p=next[0],i=1,last=0;
48     while(p&&i<=M){
49         if(!A[p][i]){
50             int pp,_last=p;
51             for(pp=next[p];pp;_last=pp,pp=next[pp]) if(A[pp][i]) break;
52             if(!pp){ i++; continue; }
53             next[_last]=next[pp],next[last]=pp,next[pp]=p;
54             p=pp;
55         }
56         for(int pp=next[p];pp;pp=next[pp]){
57             int t=1ll*A[pp][i]*inv(A[p][i])%mo;
58             for(int j=i;j<=M;j++)
59                 A[pp][j]=(A[pp][j]-1ll*A[p][j]*t%mo+mo)%mo;
60         }
61         last=p,p=next[p],i++;
62     }
63     return p;
64 }
65 void work()
66 {
67     for(int i=1;i<=N;i++) D[i]=(data){i,C[i]};
68     sort(D+1,D+N+1);
69     int p=0;
70     for(int i=1;i<=N;i++) next[p]=D[i].id,p=D[i].id;
71     next[p]=0;
72     int P=Gauss(),ans1=0,ans2=0;
73     for(p=next[0];p!=P;p=next[p]) ans1++,ans2+=C[p];
74     printf("%d %d\n",ans1,ans2);
75 }
76 int main()
77 {
78     data_in();
79     work();
80     return 0;
81 }

 

 

posted @ 2018-03-21 15:06  KKKorange  阅读(150)  评论(0编辑  收藏  举报