NOI2012 美食節 動態加邊維護費用流

2021-07-16 23:41:34 字數 1637 閱讀 9266

現在有

n 種人,每種人有pi

個,還有

m 個廚師,第

j個廚師給第

i 種人做菜需要時間ti

,j,並且同一時間乙個廚師只能做一道菜。每個人的權值是這個人等待的時間。問所有人的權值和最小是多少。n≤

40 m≤

100 ∑p

i≤800 設s

um=∑

pi。

我們考慮用網路流做這題,我們把第

i 個廚師差拆成su

m個點,第

k 個點表示這個廚師做的倒數第

k道菜,每個點向每個人

j 連一條流量為

1,費用為tj

,i∗k

,向t 連一條流量為

1,費用為

0 的邊。每個人想

s連一條流量為pi

,費用為

0 的邊。顯然跑一次最小費用最大流的費用就是答案。

但是這樣肯定會超時!因為邊太多了。所以我們可以考慮動態加邊,對於每個廚師,做完代表倒數

k個菜的點才把代表倒數k+

1 個菜的點加進去即動態加邊,就能大大減少網路流遍歷邊的時間,並且我們不用但新是否會流了代表倒數第

k 個菜的點,但是沒流代表倒數第k−

1個菜的點,因為我們肯定會優先流費用小的邊。

//yxuanwkeith

#include

#include

#include

using

namespace

std;

const

int maxn = 100000;

int all, s, t, n, m, min, p[50], t[50][1000], d[maxn];

int tot, last[maxn], go[maxn * 2], len[maxn * 2], next[maxn * 2], cost[maxn * 2], dis[maxn];

bool flag[maxn], bz[maxn];

void open(int u, int v, int flow, int cost)

void link(int u, int v, int flow, int cost)

void add(int num, int cnt)

int dfs(int now, int flow)

int use = 0;

bz[now] = 1;

for (int p = last[now]; p; p = next[p]) }}

return use;

}void go_flow() }}

bz[now] = 0;

}if (dis[t] == inf) return;

dfs(s, inf);

}}int main()

s = 0, t = all * m + n + 1;

tot = 1;

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

for (int i = 1; i <= m; i ++) add(i, 1);

go_flow();

printf("%d\n", min);

}

費用流 動態加邊 NOI2012 美食節

輸入檔案的第1行包含兩個正整數n和m,表示菜品的種數和廚師的數量。第2行包含n個正整數,其中第i個數為pi,表示點第i種菜品的人數。接下來有n行,每行包含m個非負整數,這n行中的第i行的第j個數為ti,j,表示第j個廚師製作第i種菜品所需的時間。輸入檔案中每行相鄰的兩個數之間均由乙個空格隔開,行末均...

NOI2012 美食節(網路流)

本題是修車的資料加強版 有數量限制和花費,考慮費用流建模 顯然,源點連線每個菜,流量為 p i 廚師連向匯點,流量為 inf 但是菜 i 和廚師 j 在不同時間的花費是不同的,具體來說,當它是倒數第 k 道菜時,它的花費為 k times a 將廚師拆點,分別對應倒數第 k 道菜,連線菜和廚師,流量...

NOI2012 美食節 費用流

題目描述 題解 一開始按照修車那題的思路搞了個費用流,就是把廚師拆成tim個點,表示他是倒數第幾個做的,然後邊權就是對後面的人的代價和,然後t到飛起。原因是直接把圖建出來導致圖的規模過大,然後spfa就死了。所以我們可以動態加邊,每增廣一次就加乙個點。include include include ...