題目連結: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 1010const 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;}