题意
即将启动的奥运新项目要招募一批短期志愿者。
经过估算,这个项目需要n 天才能完成,其中第i 天至少需要bi 个人。
一共有m 类志愿者可以招募。其中第i 类可以从第Si 天工作到第Ti 天,招募费用是每人ci 元。求尽量少的费用招募足够的志愿者。
n≤1000,m≤10000
题解
这题官方做法是巧妙的建图跑费用流,但是我想不到。直接上单纯形也是可以过的。
把题目表达成线性规划:
Min:∑i=1mci∗xi
St.∑i=1maij∗xi≥bi,j=1,2,...,n
其中 aij 表示第i类人是否 (1/0) 在第 j 天工作。
这里若吧
所以我们对偶一下:
Max:∑i=1nbi∗yi
St.∑i=1naij∗yi≤ci,j=1,2,...,m
这样 (0,0,...,0) 就是初始解, 处理起来简单多了。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const double eps=1e-8;
double a[10005][1005];
int n,m,id[20005];
void Pivot(int l,int e){
swap(id[n+l],id[e]);
double t=a[l][e]; a[l][e]=1;
for(int i=0;i<=n;i++) a[l][i]/=t;
for(int i=0;i<=m;i++) if(i!=l&&fabs(a[i][e])>eps){
t=a[i][e]; a[i][e]=0;
for(int j=0;j<=n;j++) a[i][j]-=t*a[l][j];
}
}
bool Simplex(){
while(1){
int l=0,e=0; double _min=1e+50;
for(int i=1;i<=n;i++) if(a[0][i]>eps){ e=i; break; }
if(!e) break;
for(int i=1;i<=m;i++)
if(-a[i][e]<-eps&&a[i][0]/a[i][e]<_min) _min=a[i][0]/a[i][e], l=i;
if(!l) return false;
Pivot(l,e);
}
return true;
}
int main(){
freopen("bzoj1061.in","r",stdin);
freopen("bzoj1061.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%lf",&a[0][i]);
for(int i=1;i<=m;i++){
int x,y; scanf("%d%d%lf",&x,&y,&a[i][0]);
for(int j=x;j<=y;j++) a[i][j]=1;
}
for(int i=1;i<=n;i++) id[i]=i;
Simplex();
printf("%d\n",(int)(-a[0][0]+0.5));
return 0;
}