現在有
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 ...