洛谷 P3980 [NOI2008]志願者招募 費用流
題目描述
申奧成功後,布布經過不懈努力,終於成為奧組委下屬公司人力資源部門的主管。布布剛上任就遇到了一個難題:為即將啟動的奧運新專案招募一批短期志願者。經過估算,這個專案需要N 天才能完成,其中第i 天至少需要Ai 個人。 布布通過了解得知,一共有M 類志願者可以招募。其中第i 類可以從第Si 天工作到第Ti 天,招募費用是每人Ci 元。新官上任三把火,為了出色地完成自己的工作,布布希望用盡量少的費用招募足夠的志願者,但這並不是他的特長!於是布布找到了你,希望你幫他設計一種最優的招募方案。
輸入輸出格式
輸入格式:
第一行包含兩個整數N, M,表示完成專案的天數和可以招募的志願者的種類。 接下來的一行中包含N 個非負整數,表示每天至少需要的志願者人數。 接下來的M 行中每行包含三個整數Si, Ti, Ci,含義如上文所述。為了方便起見,我們可以認為每類志願者的數量都是無限多的。
輸出格式:
僅包含一個整數,表示你所設計的最優方案的總費用。
輸入輸出樣例
輸入樣例#1:
3 3
2 3 4
1 2 2
2 3 5
3 3 2
輸出樣例#1:
14
說明
1 ≤ N ≤ 1000,1 ≤ M ≤ 10000,題目中其他所涉及的資料均 不超過2^31-1。
分析:
想到網路流以後,一個直觀的想法就是源點連人,人連可以被僱傭的日子,日子連匯點,然後跑最小費用最大流。可以發現一滴流量(僱傭一個人)只能用其中一天,其實每天都是能用的。
那我們可以把點串聯或直接跨過這個區間,顯然串聯的話不同類的人會相互影響,那就只能直接跨過這個區間了。
我們設每天都要僱傭
我們可以把設為,只保證費用最小,但是費用流會為了更大的流而花費更多的錢,但是每一滴從源點到匯點的流都只表示都僱傭了一個志願者,所以我們希望的最大流是,所以從源點向點流量為
程式碼:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#define LL long long
const int inf=2147483647;
const int maxn=1007;
const int maxe=40007;
using namespace std;
int n,m,x,y,c,s,t,cnt;
LL ans;
int pre[maxn],ls[maxn],dis[maxn],v[maxn];
struct edge{
int x,y,w,c,op,next;
}g[maxe];
queue <int> q;
void add(int x,int y,int w,int c)
{
g[++cnt]=(edge){x,y,w,c,cnt+1,ls[x]};
ls[x]=cnt;
g[++cnt]=(edge){y,x,0,-c,cnt-1,ls[y]};
ls[y]=cnt;
}
bool spfa()
{
for (int i=s;i<=t;i++)
{
dis[i]=inf/2;
v[i]=0;
}
while (!q.empty()) q.pop();
dis[s]=0;
v[s]=1;
q.push(s);
while (!q.empty())
{
int x=q.front();
q.pop();
for (int i=ls[x];i>0;i=g[i].next)
{
int y=g[i].y;
if ((g[i].w) && (dis[x]+g[i].c<dis[y]))
{
dis[y]=dis[x]+g[i].c;
pre[y]=i;
if (!v[y])
{
v[y]=1;
q.push(y);
}
}
}
v[x]=0;
}
if (dis[t]==inf/2) return 0;
return 1;
}
void mcf()
{
int flow=inf,i=t;
while (i!=s)
{
flow=min(flow,g[pre[i]].w);
i=g[pre[i]].x;
}
i=t;
while (i!=s)
{
g[pre[i]].w-=flow;
g[g[pre[i]].op].w+=flow;
ans+=(LL)g[pre[i]].c*1ll*flow;
i=g[pre[i]].x;
}
}
int main()
{
scanf("%d%d",&n,&m);
s=0; t=n+2;
add(s,1,inf,0);
add(n+1,t,inf,0);
for (int i=1;i<=n;i++)
{
scanf("%d",&x);
add(i,i+1,inf-x,0);
}
for (int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&c);
add(x,y+1,inf,c);
}
while (spfa())
mcf();
printf("%lld",ans);
}