BZOJ严重卡精,要加 $long$ $double$ 才能过.
题意:求权和最小的极大线性无关组.
之前那个方法解的线性基都是基于二进制拆位的,这次不行,现在要求一个适用范围更广的方法.
考虑贪心:将向量组按照代价从小到大排序,依次考虑加入每一组向量,如果能被表示出来就加,表示不出来就不加.
你可能会举出一个反例:按照权值从小到大排序后要加入向量 $x,$ 但是后面有若干向量 $a,b,c,d...$ 能表示出 $x,$ 而 $x$ 却表示不出它们,你可能会说最优解法是加入后面那几个,而不加入 $x.$
然而,你可以列一个等式,就是 $a\times x_{1}+b\times x_{2}+c\times x_{3}....=x,$ 将 $x$ 移到左面,随便一个向量移到右面,变成 $a\times x_{1}+b\times x_{2}-x....=c\times x_{3}.$
而 $x$ 的代价显然要小于 $c,$ 所以我们上述的贪心策略是正确的.
#include <cstdio>
#include <algorithm>
#define N 600
#define eps 1e-5
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
struct Node
{
int w;
long double a[N];
}p[N];
bool cmp(Node a,Node b)
{
return a.w<b.w;
}
int n,m;
int mark[N];
int main()
{
int i,j;
// setIO("input");
scanf("%d%d",&n,&m);
for(i=1;i<=n;++i)
{
for(j=1;j<=m;++j)
{
double c;
scanf("%lf",&c);
p[i].a[j]=(long double) c;
}
}
for(i=1;i<=n;++i) scanf("%d",&p[i].w);
sort(p+1,p+1+n,cmp);
int ans=0, cnt=0, k;
for(i=1;i<=n;++i)
{
for(j=1;j<=m;++j)
{
if(p[i].a[j]>=-eps&&p[i].a[j]<=eps) continue;
if(!mark[j])
{
mark[j]=i,ans+=p[i].w,++cnt;
break;
}
else
{
long double div=(long double)p[i].a[j]/p[mark[j]].a[j];
for(k=j;k<=m;++k)
{
p[i].a[k]=(long double)(p[i].a[k]-(long double)div*p[mark[j]].a[k]);
}
}
}
}
printf("%d %d\n",cnt,ans);
return 0;
}