BZOJ 1061 志願者招募(最小費用最大流)


題目鏈接:http://61.187.179.132/JudgeOnline/problem.php?id=1061

題意:申奧成功后,布布經過不懈努力,終於 成為奧組委下屬公司人力資源部門的主管。布布剛上任就遇到了一個難題:為即將啟動的奧運新項目招募一批短期志願者。經過估算,這個項目需要N 天才能完成,其中第i 天至少需要Ai 個人。 布布通過了解得知,一共有M 類志願者可以招募。其中第i 類可以從第Si 天工作到第Ti 天,招募費用是每人Ci 元。新官上任三把火,為了出色地完成自己的工作,布布希望用盡量少的費用招募足夠的志願者,但這並不是他的特長!於是布布找到了你,希望你幫他設計一種最 優的招募方案。

思路:

例如一共需要4天,四天需要的人數依次是4,2,5,3。有5類志願者,如下表所示:


設雇佣第i類志願者的人數為X[i],每個志願者的費用為V[i],第j天雇佣的人數為P[j],則每天的雇佣人數應滿足一個不等式,如上表所述,可以列出

P[1]=X[1]+X[2]>=4

P[2]=X[1]+X[3]>=2

P[3]=X[3]+X[4]+X[5]>=5

P[4]=X[5]>=3

對於第i個不等式,添加輔助變量Y[i](Y[i]>=0),可以使其變為等式

P[1]=X[1]+X[2]-Y[1]=4

P[2]=X[1]+X[3]-Y[2]=2

P[3]=X[3]+X[4]+X[5]-Y[3]=5

P[4]=X[5]-Y[4]=3

在上述四個等式上下添加P[0]=0,P[5]=0,每次用下邊的式子減去上邊的式子,得出

① P[1]-P[0]=X[1]+X[2]-Y[1]=4

② P[2]-P[1]=X[3]-X[2]-Y[2]+Y[1]=-2

③ P[3]-P[2]=X[4]+X[5]-X[1]-Y[3]+Y[2]=3

④ P[4]-P[3]=-X[3]-X[4]+Y[3]-Y[4]=-2

⑤ P[5]-P[4]=-X[5]+Y[4]=-3

觀察發現,每個變量都在兩個式子中出現了,而且一次為正,一次為負.所有等式右邊和為0.我們將最后的五個等式進一步變形,得出以下結果

① -X[1]-X[2]+Y[1]+4=0

② -X[3]+X[2]+Y[2]-Y[1]-2=0

③ -X[4]-X[5]+X[1]+Y[3]-Y[2]+3=0

④ X[3]+X[4]-Y[3]+Y[4]-2=0

⑤ X[5]-Y[4]-3=0

可 以發現,每個等式左邊都是幾個變量和一個常數相加減,右邊都為0,恰好就像網絡流中除了源點和匯點的頂點都滿足流量平衡。每個正的變量相當於流入該頂點的 流量,負的變量相當於流出該頂點的流量,而正常數可以看作來自附加源點的流量,負的常數是流向附加匯點的流量。因此可以據此構造網絡,求出從附加源到附加 匯的網絡最大流,即可滿足所有等式。而我們還要求費用最小,所以要在X變量相對應的邊上加上權值,然后求最小費用最大流

接下來,根據上面五個等式構圖。

(1)每個等式為圖中一個頂點,添加源點S和匯點T。

(2)如果一個等式中的數字為非負整數c,從源點S向該等式對應的頂點連接一條容量為c,權值為0的有向邊;如果為負整數-c,從該等式對應的頂點向匯點T連接一條容量為c,權值為0的有向邊。

(3)如果一個變量X[i]在第j個等式中出現為-X[i],在第k個等式中出現為+X[i],從頂點j向頂點k連接一條容量為INF,權值為V[i]的有向邊。

(4)如果一個變量Y[i]在第j個等式中出現為-Y[i],在第k個等式中出現為+Y[i],從頂點j向頂點k連接一條容量為INF,權值為0的有向邊。

構圖以后,求從源點S到匯點T的最小費用最大流,費用值就是結果。

 

 

struct node
{
    int cost,flow,v,u,next;
};


node edges[N*1000];
int head[N],e,s,t;
int pre[N];


void add(int u,int v,int flow,int cost)
{
    edges[e].u=u;
    edges[e].v=v;
    edges[e].cost=cost;
    edges[e].flow=flow;
    edges[e].next=head[u];
    head[u]=e++;
}


void Add(int u,int v,int flow,int cost)
{
    add(u,v,flow,cost);
    add(v,u,0,-cost);
}


int SPFA(int s,int t)
{
    clr(pre,-1);
    int F[N],h[N],C[N],i,u,v,f,c;
    queue<int> Q;
    FOR0(i,t+1) C[i]=INF,h[i]=0,F[i]=0;
    Q.push(s); C[s]=0; F[s]=INF;
    while(!Q.empty())
    {
        u=Q.front();
        Q.pop();


        h[u]=0;
        for(i=head[u];i!=-1;i=edges[i].next)
        {
            v=edges[i].v;
            f=edges[i].flow;
            c=edges[i].cost;
            if(f>0&&C[v]>C[u]+c)
            {
                C[v]=C[u]+c;
                F[v]=min(F[u],f);
                pre[v]=i;
                if(!h[v]) h[v]=1,Q.push(v);
            }
        }
    }
    return F[t];
}


int MCMF(int s,int t)
{
    int ans=0,i,temp;
    while(temp=SPFA(s,t))
    {
        for(i=pre[t];i!=-1;i=pre[edges[i].u])
        {
            ans+=temp*edges[i].cost;
            edges[i].flow-=temp;
            edges[i^1].flow+=temp;
        }
    }
    return ans;
}


int n,m,d[N];


int main()
{
    RD(n,m); clr(head,-1); e=0; s=0; t=n+2;
    int i,u,v,c,temp;
    FOR1(i,n) RD(d[i]);
    FOR1(i,m)
    {
        RD(u,v,c);
        Add(u,v+1,INF,c);
    }
    FOR1(i,n+1)
    {
        temp=d[i]-d[i-1];
        if(temp>=0) Add(s,i,temp,0);
        else Add(i,t,-temp,0);
        if(i>1) Add(i,i-1,INF,0);
    }
    PR(MCMF(s,t));
}

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM