BZOJ1061 NOI2008 志愿者招募 单纯形
题意:给定M个志愿者和工作时间的长度N,每个志愿者由工作时间[l,r]和费用c来描述,每个单位时间需要t名志愿者,保证有解,求最少总花费。
题解:这个题标算貌似是费用流啊,不太清楚……总而言之设x[i]为i这个人要不要,b[i]为各个时间所需的志愿者数量,a[i][j]为i时间j这名志愿者能不能起作用,c[i]为i的费用,然后就是裸的线性规划
#include <cmath> #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; #define INF 1e10 #define eps 1e-6 const int MAXN=1000+2; const int MAXM=10000+2; int N,M; double a[MAXM][MAXN],b[MAXM],c[MAXN]; double Pivot(int l,int e){ b[l]/=a[l][e]; for(int i=1;i<=N;i++) if(i!=e) a[l][i]/=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){ b[i]-=a[i][e]*b[l]; for(int j=1;j<=N;j++) if(j!=e) a[i][j]-=a[i][e]*a[l][j]; a[i][e]=-a[i][e]*a[l][e]; } double ret=c[e]*b[l]; for(int i=1;i<=N;i++) if(i!=e) c[i]-=c[e]*a[l][i]; c[e]=-c[e]*a[l][e]; return ret; } double Simplex(){ int e,l; double ret=0; while(1){ e=-1; for(int i=1;i<=N;i++) if(c[i]>0){ e=i; break; } if(e==-1) return ret; double t=INF; for(int i=1;i<=M;i++) if(a[i][e]>eps && b[i]/a[i][e]<t) t=b[i]/a[i][e],l=i; if(t==INF) return INF; ret+=Pivot(l,e); } } int main(){ cin >> N >> M; for(int i=1;i<=N;i++) scanf("%lf",c+i); for(int i=1,x,y,z;i<=M;i++){ scanf("%d %d %d",&x,&y,&z); for(int j=x;j<=y;j++) a[i][j]=1; b[i]=z; } cout << (int)(Simplex()+0.5) << endl; return 0; }