1. 程式人生 > >bzoj 3550: [ONTAK2010]Vacation 單純形

bzoj 3550: [ONTAK2010]Vacation 單純形

題意

有3N個數,你需要選出一些數,首先保證任意長度為N的區間中選出的數的個數<=K個,其次要保證選出的數的個數最大。
N<=200,K<=10。

分析

裸的單純形,對偶都不用。
話說不知道裸的費用流能不能跑過去。算了一下貌似是可以的。不過懶得打了。

程式碼

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace
std; const int N=605; const double eps=1e-7; int n,k,m; double c[N],b[N],a[N*2][N],v; void pivot(int e,int l) { for (int i=1;i<=n;i++) if (i!=e) a[l][i]/=a[l][e]; b[l]/=a[l][e];a[l][e]=1/a[l][e]; for (int i=1;i<=m;i++) if (i!=l&&fabs(a[i][e])>eps) { for
(int j=1;j<=n;j++) if (j!=e) a[i][j]-=a[i][e]*a[l][j]; b[i]-=b[l]/a[i][e];a[i][e]=-a[i][e]*a[l][e]; } v+=b[l]*c[e]; for (int i=1;i<=n;i++) if (i!=e) c[i]-=c[e]*a[l][i]; c[e]=-c[e]*a[l][e]; } double simplex() { while (1) { int e,l; for (int
i=1;i<=n;i++) if (c[e=i]>eps) break; if (c[e]<eps) return v; double tmp=1e10; for (int i=1;i<=m;i++) if (a[i][e]>eps&&b[i]/a[i][e]<tmp) tmp=b[i]/a[i][e],l=i; pivot(e,l); } } int main() { scanf("%d%d",&n,&k); for (int i=1;i<=n*3;i++) { scanf("%lf",&c[i]); if (i+n-1<=n*3) { m++; for (int j=0;j<n;j++) a[m][i+j]=1; } b[m]=k; } for (int i=1;i<=n*3;i++) a[++m][i]=1,b[m]=1; n*=3; double ans=simplex(); printf("%d",(int)(ans+0.1)); return 0; }