P3980 NOI2008 志願者招募 網路流

2022-05-01 13:54:09 字數 1703 閱讀 1852

題意: 一共有n 天  每天需要ai個志願者   

有m種志願者 每種志願者可以從  第si 天工作到ti 天  每個需要ci元     問花最少的錢滿足每天的需求

顯然是費用流

如果正常連邊的話  每個志願者對其輻射的天非常難處理 

可以採用時間軸的連法:

源點連第一天

匯點連最後一天

容量為inf費用為0

這樣跑網路流是沿時間流的(就是依次解決每一天的問題)

然後每一天向後一天連一條容量為inf-a[i]

費用為0的邊

為什麼容量為inf-a[i]

這就相當於少了a[i]

得用帶權邊補全inf

這就是志願者連續乾時沿這條邊跑

因為連續幹不花錢

所以優先選這種邊

然後將每一類志願者s[i]與t[i]+1連一條容量為

inf花費為c[i]的邊

當連續幹的人不夠時

就得使勁往裡塞人

#includeusing

namespace

std;

//input by bxd

#define rep(i,a,b) for(int i=(a);i<=(b);i++)

#define repp(i,a,b) for(int i=(a);i>=(b);--i)

#define ri(n) scanf("%d",&(n))

#define rii(n,m) scanf("%d%d",&n,&m)

#define riii(n,m,k) scanf("%d%d%d",&n,&m,&k)

#define rs(s) scanf("%s",s);

#define ll long long

#define pb push_back

#define inf 0x3f3f3f3f

#define clr(a,v) memset(a,v,sizeof a)

/////////////////////////////////

/const

int n=100001

;ll maxflow,mincost;

intlast[n],pre[n],dis[n],flow[n];

bool

vis[n];

struct

edgeedge[n

<<1

];int pos=1

,head[n];

void

init()

queue

q;void add(int

from,int to,int flow,int dis)//

flow流量 dis費用

bool spfa(int s,int

t) }}}

return pre[t]!=-1;}

void mcmf(int s,int

t) }

}int

a,b,s,t,n,m,c,x;

intmain()

s=n+2,t=s+1

; add(s,

1,inf,0);add(n+1,t,inf,0

); mcmf(s,t);

printf(

"%lld\n

",mincost);

return0;

}

view code

洛谷 P3980 NOI2008 志願者招募

我居然現在才會用費用流解線性規劃 當然這裡解決的一類問題比較特殊 以式子作為點,變數作為邊,然後要求就是變數在不同的式子裡出現了兩次,係數一次為 1,一次為 1 這樣的話就作為了乙個出度和乙個入度,和邊正好對應了 我們設每種志願者選擇人數是 x 我們的限制是 left x geq 0 x x geq...

luoguP3980 NOI2008 志願者招募

這道題的難點主要在於處理乙個人可以對區間產生貢獻這個限制。我們之前都是將乙個人當成流量,但是這一容量的流量可以對乙個區間的點產生貢獻,這就導致這個問題無法處理。於是考慮怎麼將乙個點可以對乙個區間產生貢獻在圖上表示出來 我們考慮每一天,從 s 向 1 連容量為 inf 的邊,從 i 向 i 1 連容量...

NOI2008 志願者招聘

文化課 競賽雙廢物又來水題解了。把下界限制轉化為一條邊的流量下界,這樣就是最小費用上下界最大流。加入幾個新值,其條件正好為 ge 0 將其當做一條流量,這樣不等式就變成了等式,我們可以利用流量守恆,用點的流滿 leftrightarrow 等式成立,這樣就變成了乙個最小費用最大流,去掉了上下界的影響...