網路流24題(十八)
阿新 • • 發佈:2021-10-26
網路流24題(十八)
十八、分配問題
題目描述
有 nn 件工作要分配給 nn 個人做。第 ii 個人做第 jj 件工作產生的效益為 c_{ij}cij 。試設計一個將 nn 件工作分配給 nn 個人做的分配方案,使產生的總效益最大。
輸入格式
檔案的第 1 行有 1 個正整數 n,表示有 n 件工作要分配給 n 個人做。
接下來的 n 行中,每行有 n 個整數 \(c_{ij}\),表示第 i 個人做第 j 件工作產生的效益為 \(c_{ij}\)。
輸出格式
兩行分別輸出最小總效益和最大總效益。
題解
模型
二分圖最大權匹配
建圖
把所有人看做二分圖中頂點\(X_i\),所有任務看做二分圖中頂點\(Y_i\),建立附加源S匯T。
- 從S向每個\(X_i\)連一條容量為\(1\),費用為0的有向邊。
- 從每個\(Y_i\)向T連一條容量為\(1\),費用為0的有向邊。
- 從每個\(X_i\)向每個\(Y_j\)連線一條容量為1,費用為\(c_{ij}\)的有向邊。
求最小費用最大流,最小費用流值就是最少最小效益,求最大費用最大流,最大費用流值就是最大效益。
程式碼
#include <iostream> #include <queue> #include <stack> #include <map> #include <cstring> using namespace std; #define ll long long const ll inf = 0x3f3f3f3f; const int N = 5000,M = 5e4+50; ll head[N],cnt = 1; struct Edge{ ll to,w,cost,nxt; }edge[M*2]; void add(ll u,ll v,ll w,ll c){ edge[++cnt] = {v,w,c,head[u]}; head[u] = cnt; } void add2(ll u,ll v,ll w,ll cost){ add(u,v,w,cost); add(v,u,0,-cost); } ll s,t,dis[N],cur[N]; bool inq[N],vis[N]; queue<ll>Q; bool spfa(){ while(!Q.empty()) Q.pop(); copy(head,head+N,cur); fill(dis,dis+N,inf); dis[s] = 0; Q.push(s); while(!Q.empty()){ ll p = Q.front(); Q.pop(); inq[p] = false; for(ll e = head[p];e;e = edge[e].nxt){ ll to = edge[e].to,vol = edge[e].w; if(vol > 0 && dis[to]>dis[p]+edge[e].cost){ dis[to] = dis[p] + edge[e].cost; if(!inq[to]){ Q.push(to); inq[to] = true; } } } } return dis[t] != inf; } ll dfs(ll p = s,ll flow = inf){ if(p == t) return flow; vis[p] = true; ll rmn = flow; for(ll eg = cur[p];eg && rmn;eg = edge[eg].nxt){ cur[p] = eg; ll to = edge[eg].to,vol = edge[eg].w; if(vol > 0 && !vis[to]&&dis[to] == dis[p]+edge[eg].cost){ ll c = dfs(to,min(vol,rmn)); rmn -= c; edge[eg].w -= c; edge[eg^1].w += c; } } vis[p] = false; return flow-rmn; } ll maxflow,mincost; void dinic(){ maxflow = 0,mincost = 0; while(spfa()){ ll flow = dfs(); maxflow += flow; mincost += dis[t]*flow; } } ll n; ll c[N][N]; void init1(){ for(ll i = 1;i <= n;i++)add2(s,i,1,0); for(ll i = 1;i <= n;i++)add2(i+n,t,1,0); for(ll i = 1;i <= n;i++){ for(ll j = 1;j <= n;j++){ add2(i,j+n,1,c[i][j]); } } dinic(); cout<<mincost<<endl; } void init2(){ memset(head,0, sizeof head); cnt = 1; for(ll i = 1;i <= n;i++)add2(s,i,1,0); for(ll i = 1;i <= n;i++)add2(i+n,t,1,0); for(ll i = 1;i <= n;i++){ for(ll j = 1;j <= n;j++){ add2(i,j+n,1,-c[i][j]); } } dinic(); cout<<-mincost<<endl; } int main(){ //ios::sync_with_stdio(false); cin>>n; s = 0,t = 2*n+1; for(ll i = 1;i <= n;i++){ for(ll j = 1;j <= n;j++){ cin>>c[i][j]; } } init1(); init2(); return 0; }