bzoj1061 志願者招募

2021-09-22 16:46:35 字數 1501 閱讀 9110

題意:給m類志願者,第i個志願者從第 l[ i ] 天工作到第  r[ i ] 天,費用為c[ i ]。每種志願者可以選擇無限多人。

每一天都有給定的最少志願者數目要求a[ i ],求費用最小的選擇方案,輸出費用。

思路:明顯是一道線性規劃可以解決的問題,但我不會寫單純型。聽溪哥說線性規劃都有網路流的等價形式,不過我在網上沒有找到,知道的dalao可以給我留個言嗎。

進入正題:

假設第i種志願者選xi人,則有方程 

a1 * x1 >= a[ 1 ]

a2 * x2 >= a[ 2 ]

a3 * x3 >= a[ 3 ]

an * xn >= a[ n ]

除此之外在開頭新增  方程0 = 0。在結尾新增 0 = 0.

將a[ i ] 移動到 方程左端後變為網路流流量平衡的形式。n + 1個方程對應n+1個節點。

我們注意到每個變數在方程中連續出現,則差分之後每個變數在兩個方程**現,並且乙個係數為正,乙個係數為負。

這就對應網路流中的一條邊,這是這個演算法的精髓所在,如果xi多次出現的話對應網路流中的多條邊,則這個演算法直接涼涼。

而常數項就與原點或匯點連邊。

這裡留個坑,一般形式的線性規劃如何轉化為網路流求解。以後要是做到這類題來補上。

#include using namespace std;

typedef long long ll;

const ll maxn = 10000;

const ll maxm = 1000000;

const ll inf = 0x3f3f3f3f3f3f3f3f;

struct mcmf

void add(ll x,ll y,ll cap,ll c)

bool spfa(ll s,ll t)

d[s] = 0;

vis[s] = true;

q.push(s);

while(!q.empty())}}

}if(pre[t] == -1)return false;

else return true;

}ll mincost(ll s,ll t,ll &cc)

for(ll cure = pre[t];cure != -1;cure = pre[ ver[cure^1] ])

flow += mn;

}return flow;

}} g;

ll a[maxn];

int main()

else if( cur < 0 )

}if( a[n] ) g.add( ss,n+1,a[n],0 );

for( ll i = 1;i <= m;i++ )

for( ll i = 1;i <= n;i++ )

ll cost;

ll maxflow = g.mincost(ss,tt,cost);

printf("%lld",cost);

return 0;

}

bzoj 1061 志願者招募

明顯的線性規劃網路流,據說當時考場上就1個人a了?a i j 表示第i種志願者第j天是否工作 p i 表示第i種志願者的人數 sigma a i x p i need x 補充函式y i 則sigma a i x p i need x y x 差分,start i 表示第i種志願者開始工作的時間,e...

BZOJ 1061, 志願者招募

傳送門 最小化招聘給定不同型別志願者,以滿足每日不同人數要求的費用總和。由線性規劃轉化為最小費用最大流來處理。一般按如下步驟進行操作 新增鬆弛變數,將不等號都變為等號。分別用下乙個式子減去上乙個式子,如果每個變數只出現了兩次且符號一正一負,那麼可以轉化為費用流。對於每個式子建立乙個點,那麼每個變數對...

BZOJ 1061 志願者招募

思路 可以用不等式的改裝變成費用流.將不等式列出,如果有負的常數,那麼就從等式連向t,如果是正的就從s連向等式,流量為常數,費用為0。如果是變數,那麼找出都有這個變數的兩個等式,從負的連向正的流量為inf的邊,如果有費用,那就再加上費用。1 include2 include3 include4 in...