網絡流二十四題 分配問題
阿新 • • 發佈:2018-07-05
ret fine 輸入 head 二分圖 range 分配 inf ont
一個最大一個最小,取反一下就可以辣
分配問題
題目描述
有 nn 件工作要分配給 nn 個人做。第 ii 個人做第 jj 件工作產生的效益為 c_{ij}cij? 。試設計一個將 nn 件工作分配給 nn 個人做的分配方案,使產生的總效益最大。
輸入輸出格式
輸入格式:
文件的第 11 行有 11 個正整數 nn ,表示有 nn 件工作要分配給 nn 個人做。
接下來的 nn 行中,每行有 nn 個整數 c_{ij}cij? ??,表示第 ii 個人做第 jj 件工作產生的效益為 c_{ij}cij? 。
輸出格式:
兩行分別輸出最小總效益和最大總效益。
輸入輸出樣例
輸入樣例#1:5 2 2 2 1 2 2 3 1 2 4 2 0 1 1 1 2 3 4 3 3 3 2 1 2 1輸出樣例#1:
5 14
說明
1≤n≤100
一個人只能修一個工件
2018.7.5測試T3
當時打出了最小費用,卻沒敢做,打了10分的搜索暴力(;′⌒`)
其實挺簡單的
二分圖,左邊是人,右邊的工作,
建立一個超級源點,一個超級匯點
建的邊流量都是1(一個人只能修一個工件)
與源點或匯點相連的費用全是0
人與工作之間的費用是他們之間的效益
一個最大一個最小,取反一下就可以辣
1 #include <iostream> 2 #include <queue> 3 #include <cstring> 4 #include <cstdio> 5 #define inf 0x3f3f3f3f 6 using namespace std; 7 8 int n,s,t; 9 int a[101][101]; 10 struct node{ 11 int u,v,flow,spend,next; 12 }e[100100]; 13 int head[100100],tot=1; 14 intfrom[100100],vis[100100],dis[100100]; 15 int ans; 16 17 void add_node(int a,int b,int f,int s) { 18 e[++tot]=(node){a,b,f,s,head[a]}; 19 head[a]=tot; 20 } 21 bool SPFA() { 22 memset(dis,inf,sizeof(dis)); 23 memset(vis,0,sizeof(vis)); 24 queue<int> q; 25 q.push(s); 26 dis[s]=0; 27 while(!q.empty()) { 28 int x=q.front(); 29 q.pop();vis[x]=0; 30 for(int i=head[x];i;i=e[i].next) { 31 int v=e[i].v; 32 int u=e[i].u; 33 int f=e[i].flow; 34 int s=e[i].spend; 35 if(dis[u]+s < dis[v]&& f>0) { 36 dis[v]=dis[u]+s; 37 from[v]=i; 38 if(!vis[v]) { 39 vis[v]=1; 40 q.push(v); 41 } 42 } 43 } 44 } 45 return dis[t]!=inf; 46 47 } 48 void work() { 49 int mn=inf; 50 for(int i=t;i!=s;i=e[from[i]].u) 51 mn=min(mn,e[from[i]].flow); 52 for(int i=t;i!=s;i=e[from[i]].u) { 53 e[from[i]].flow-=mn; 54 e[from[i]^1].flow+=mn; 55 ans+=mn*e[from[i]].spend; 56 } 57 } 58 59 int main() 60 { 61 scanf("%d",&n); 62 //1到n代表人 63 //n+1到n+n代表工作 64 //0代表超級源點 65 //n+n+1代表超級匯點 66 for(int i=1;i<=n;++i) 67 for(int j=1;j<=n;++j) 68 scanf("%d",&a[i][j]),add_node(i,j+n,1,a[i][j]),add_node(j+n,i,0,-a[i][j]); 69 s=0,t=n+n+1; 70 for(int i=1;i<=n;++i)add_node(s,i,1,0),add_node(i,s,0,0),add_node(n+i,t,1,0),add_node(t,n+i,0,0); 71 72 //建邊後直接套板子 73 while(SPFA()) work(); 74 printf("%d\n",ans); 75 76 //清空再來一遍, 存一遍的騷操作蒟蒻表示掌握不來╮(╯▽╰)╭ 77 memset(e,0,sizeof(e)); 78 memset(head,0,sizeof(head)); 79 memset(from,0,sizeof(from)); 80 memset(vis,0,sizeof(vis)); 81 memset(dis,0,sizeof(dis)); 82 ans=0;tot=1; 83 84 //基本就是上面在復制一遍 85 for(int i=1;i<=n;++i) 86 for(int j=1;j<=n;++j) 87 add_node(i,j+n,1,-a[i][j]),add_node(j+n,i,0,a[i][j]); 88 s=0,t=n+n+1; 89 for(int i=1;i<=n;++i)add_node(s,i,1,0),add_node(i,s,0,0),add_node(n+i,t,1,0),add_node(t,n+i,0,0); 90 while(SPFA()) work(); 91 printf("%d",-ans); 92 return 0; 93 }
網絡流二十四題 分配問題