题目链接:bzoj3550
题目大意:
有3N个数,你需要选出一些数,首先保证任意长度为N的区间中选出的数的个数<=K个,其次要保证选出的数的个数最大。
题解:
单纯形
设xi为第i个数取的次数,然后按题目说的弄限制就好了。哦,再加上xi≤1。
连对偶都不用。
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iostream>
#include<algorithm>
using namespace std;
#define maxn 1010
const double inf=1e15;
const double eps=0.00000001;
int n,m;double a[maxn][maxn];
double myabs(double x){return (x<0)?-x:x;}
void pivot(int l,int e)
{
double tt=a[l][e];a[l][e]=1;
int i,j;
for (i=0;i<=n;i++) a[l][i]/=tt;
for (i=0;i<=m;i++)
if (i!=l && myabs(a[i][e])>eps)
{
double p=a[i][e];a[i][e]=0;
for (j=0;j<=n;j++)
a[i][j]-=a[l][j]*p;
}
}
bool simplex()
{
while (1)
{
int i,l,e;l=e=0;
for (i=1;i<=n;i++)
if (a[0][i]>eps && !e) {e=i;break;}
double minn=inf;
if (!e) break;
for (i=1;i<=m;i++)
if (a[i][e]>eps && a[i][0]/a[i][e]<minn) {minn=a[i][0]/a[i][e];l=i;}
if (!l) return false;
pivot(l,e);
}return true;
}
int main()
{
//freopen("a.in","r",stdin);
//freopen("a.out","w",stdout);
int k,i,j,sum;
scanf("%d%d",&n,&k);
sum=n*3;
for (i=1;i<=sum;i++)
scanf("%lf",&a[0][i]);
for (i=1;i<=sum-n+1;i++)
{
a[i][0]=k;
for (j=1;j<=n;j++)
a[i][i+j-1]=1;
}
m=sum-n+1;n=sum;
for (i=1;i<=n;i++) a[++m][i]=1,a[m][0]=1;
if (simplex()) printf("%d\n",(int)(-a[0][0]+0.5));
else printf("-1\n");
return 0;
}