NOI2008 志願者招聘

2022-04-29 05:51:10 字數 2868 閱讀 9732

文化課 + 競賽雙廢物又來水題解了。

把下界限制轉化為一條邊的流量下界,這樣就是最小費用上下界最大流。

加入幾個新值,其條件正好為 \(\ge 0\),將其當做一條流量,這樣不等式就變成了等式,我們可以利用流量守恆,用點的流滿 $\leftrightarrow $ 等式成立,這樣就變成了乙個最小費用最大流,去掉了上下界的影響。

其實這兩種思路本質好像是一致的...

那麼建立網路 \(g\):

這樣,每個志願者相當於在流網路的一單位的流量流過了乙個環,這個問題變成了最小費用無源匯上下界可行流,我們都知道可行流的可行判定經過轉化就是跑到最大流,所以轉化完後用最小費用最大流就行了。

\(o(n^2m)\) 複雜度真棒

這題 acwing 咋這麼卡常啊

#include #include #include #define rint register int

typedef long long ll;

using namespace std;

const int n = 1005, m = (n * 2 + 10000) * 2, inf = 0x3f3f3f3f;

int n, m, a[n], incf[n], d[n], q[n], pre[n];

int head[n], nume = 1, s, t;

bool vis[n];

ll ans;

struct e e[m];

void inline add(int u, int v, int w, int c) ;

head[u] = nume;

e[++nume] = (e) ;

head[v] = nume;

}bool inline spfa()

}} }

return d[t] != inf;

}void inline update()

ans += (ll)d[t] * incf[t];

}int main()

for (rint i = 1, s, t, c; i <= m; i++)

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

while (spfa()) update();

printf("%lld\n", ans);

return 0;

}

設一些新的變數:

這樣我們就可以列出 \(n\) 個等式,對於第 \(i\) 個等式(針對第 \(i\) 天的匹配情況)

\[a_i + b_i = \displaystyle \sum_ d_j

\]但是為了讓每個變數在流網路中、在每個等式中都相等,所以我們得讓每個變數至多出現在兩個式子中,(如果出現在乙個式子,就可以將其到源匯點的費用改了,這樣就是費用對應上了,如果兩個式子,可以從本該連向匯點的邊直接連向本該從源點出的邊,這樣費用對應。這裡本人實力還是非常菜,很可能講了一些玄學的東西,求大佬們輕噴。)

由於每個 \(j\) 影響的 \(i\) 是連續的一段,所以我們可以將式子前後加入兩個 \(0 = 0\),然後將式子差分(這是一步等價變換)這樣每個 \(d_j, b_i\) 都恰好會出現在兩個式子之中。

對於第 \(i\) 個等式而言,差分後的式子:

\[-a_ - b_ + a_i + b_i = \displaystyle -\sum_d_j+\sum_d_j

\]我們把式子移項,讓每一項都是正的:

\[a_i + b_i + \displaystyle\sum_ d_j = a_+b_+\sum_d_j

\]這樣,我們可以把等式看作乙個點的流量守恒等式,等式左右兩側分別是流入該點/流出改點的流量,我們建立流網路:

這樣,在流網路跑到的最大流 = 從 \(s\) 出發所有容量(滿足常量的強行限制) \(\leftrightarrow\) 差分等式成立 \(\leftrightarrow\) 原始等式成立 \(\leftrightarrow\) 乙個滿足條件的方案

所以,原問題最小費用 \(\leftrightarrow\) 最小費用最大流

\(o(n^2m)\)

這個**過不去acwing。。坑

#pragma gcc optimize("ofast","-funroll-loops")

#include #include #include #define rint register int

typedef long long ll;

using namespace std;

const int n = 1005, m = (n * 3 + 10000) * 2, inf = 0x3f3f3f3f;

int n, m, a[n], incf[n], d[n], q[n], pre[n];

int head[n], nume = 1, s, t;

bool vis[n];

ll ans;

struct e e[m];

void inline add(int u, int v, int w, int c) ;

head[u] = nume;

e[++nume] = (e) ;

head[v] = nume;

}bool inline spfa()

}} }

return d[t] != inf;

}void inline update()

ans += (ll)d[t] * incf[t];

}int main()

for (rint i = 1, s, t, c; i <= m; i++)

while (spfa()) update();

printf("%lld\n", ans);

return 0;

}

NOI 2008 志願者招募

考慮用 p i 表示第 i 天實際招收的人數,我們假設我們有三種志願者,分別是 1 to 2,1 to 3 2 to 3 我們招手的人數分別是 b 1,b 2,b 3 那麼第一天實際人數就是 p 1 b 1 b 2 geq a 1 同理我們把三個不等式寫出來 b 1 b 2 ge a 1 b 1 b...

NOI2008志願者招募

申奧成功後,布布經過不懈努力,終於成為奧組委下屬公司人力資源部門的主管。布布剛上任就遇到了乙個難題 為即將啟動的奧運新專案招募一批短期志願者。經過估算,這個專案需要n 天才能完成,其中第i 天至少需要ai 個人。布布通過了解得知,一共有m 類志願者可以招募。其中第i 類可以從第si 天工作到第ti ...

NOI2008 志願者招募

oj題號 bzoj1061 題目大意 有 n 個任務,m 個志願者,完成每個任務 i 至少需要 a i 個人,每個人只有在 s i 到 t i 的時候有空,並需要被支付 c i 的報酬,求完成所有任務的最小支出。思路 先挖空後補空 將每個時間抽象成點,並在時間軸的兩端增加源匯 s 和 t 每個相鄰的...