題目鏈接: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)); }