1. 程式人生 > >POJ-3469 Dual Core CPU (最小割)

POJ-3469 Dual Core CPU (最小割)

Dual Core CPU

題意

在這裡插入圖片描述

思路

照書上的話來說,用最小的費用將物件分成兩個集合的問題,常常可以轉換成最小割問題,這道題就是一道典型的例子。

具體的還需要證明

記在核A上執行的模組集合是S,而在核B上執行的模組集合為T。考慮以模組為頂點,並且還有額外的源點s和匯點t的圖。我們也記圖s-t割所對應的包含s的頂點集合為S,包含t的集合為T,然後來考察他們之間的對應關係。此時花費的總和是 iSAi+iTBi+aiT,biSwi+aiS,biTwi \sum_{i\in S} A_i + \sum_{i\in T}B_i + \sum_{a_i \in T, b_i \in S}w_i + \sum_{a_i \in S, b_i \in T}w_i

如果我們可以通過合適的建邊來使得花費的總和等價於割的容量的話,那麼為了求最小花費,執行求最小割就好了。

那麼讓我們一步步來建立滿足這個條件的圖吧。首先,考慮對應 iSAi\sum_{i \in S} A_i 的邊。這是頂點屬於S時的費用,所以,只要從每個模組向t連一條容量為Ai的邊。

而對於 iTBi\sum _{i \in T} B_i 也只需從s向每個模組連一條容量為Bi的邊即可。

接下來考慮 aiS,biTwi\sum_{a_i \in S,b_i \in T} w_i

這是當ai屬於S而bi屬於T時所產生的費用,只需從模板ai向模組bi連一條容量為wi的邊即可。

最後一塊,同理上一種處理方法。

圖如下。

在這裡插入圖片描述

程式碼

#include <iomanip>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <cstdio>
#include <string>
#include <stack>
#include <cmath>
#include <ctime>
#include <list> #include <set> #include <map> #include <queue> #include <vector> #include <sstream> #include <memory> #include <iostream> #include <algorithm> using namespace std; #define rep(i,j,k) for(int i = (int)j;i <= (int)k;i ++) #define per(i,j,k) for(int i = (int)j;i >= (int)k;i --) #define debug(x) cerr<<#x<<" = "<<(x)<<endl #define mmm(a,b) memset(a,b,sizeof(a)) #define pb push_back typedef double db; typedef long long ll; const int MAXN = (int)1e5+7; const int INF = (int)0x3f3f3f3f; // 用於表示表示邊的結構體(終點、容量、反向邊) struct edge{ int to,cap,rev; edge(int to = 0,int cap = 0,int rev = 0):to(to),cap(cap),rev(rev){} }; int N,M; vector<edge> G[MAXN]; int level[MAXN]; //頂點到源點的距離標號 int iter[MAXN]; //當前弧,在其之前的邊已經沒有用了 //向圖中增加一條從s到t容量為cap的邊 void add_edge(int from,int to,int cap) { G[from].pb(edge(to,cap,G[to].size())); G[to ].pb(edge(from,0,G[from].size()-1)); } //通過BFS計算從源點出發的距離標號 void bfs(int s){ mmm(level,-1); queue<int> qu; level[s] = 0; qu.push(s); while (!qu.empty()) { int v = qu.front(); qu.pop(); rep(i,0,G[v].size()-1) { edge &e = G[v][i]; if (e.cap > 0 && level[e.to] < 0) { level[e.to] = level[v] + 1; qu.push(e.to); } } } } //通過DFS尋找增廣路 int dfs(int v,int t,int f) { if (v == t) return f; for (int &i = iter[v];i < G[v].size();i ++) { edge &e = G[v][i]; if (e.cap > 0 && level[v] < level[e.to]) { int d = dfs(e.to,t,min(f,e.cap)); if (d > 0) { e.cap -= d; G[e.to][e.rev].cap += d; return d; } } } return 0; } //求解從s到t的最大流 int max_flow(int s,int t){ ll flow = 0; for (;;) { bfs(s); if (level[t] < 0) return flow; mmm(iter,0); int f; while ((f = dfs(s,t,INF)) > 0) flow += f; } } void init(){ rep(i,1,N) G[i].clear(); } leopold int main() { int n,m; scanf("%d %d",&n,&m); N = n; int s = ++N; int t = ++N; rep(i,1,n) { int a,b; scanf("%d %d",&a,&b); add_edge(s,i,a); add_edge(i,t,b); }h rep(i,1,m) { int u,v,w; scanf("%d %d %d",&u,&v,&w); add_edge(u,v,w); add_edge(v,u,w); } int ans = max_flow(s,t); printf("%d\n",ans); }