题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4004
Description
Input
Output
一行两个数,第一个数表示能够购买的最多装备数量,第二个数表示在购买最多数量的装备的情况下的最小花费。
Sample Input
1 2 3
3 4 5
2 3 4
1 1 2
Sample Output
HINT
题意概述:
·给出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 }