首页 > 代码库 > BZOJ1061 NOI2008 志愿者招募 单纯形

BZOJ1061 NOI2008 志愿者招募 单纯形

题意:给定M个志愿者和工作时间的长度N,每个志愿者由工作时间[l,r]和费用c来描述,每个单位时间需要t名志愿者,保证有解,求最少总花费。

题解:

技术分享

技术分享

(公式太多就用图片代替了QAQ)

这个题标算貌似是费用流啊,不太清楚……总而言之设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-6const 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;}
View Code

 

BZOJ1061 NOI2008 志愿者招募 单纯形