洛谷 P4014:「分配问题」
洛谷 P4014:「分配问题」
题目描述
有n件工作要分配给n个人做.第i个人做第j件工作产生的效益为Cij .试设计一个将n件工作分配给n个人做的分配方案,使产生的总效益最大.
输入格式
文件的第1行有1个正整数n,表示有n件工作要分配给n个人做. 接下来的n行中,每行有n个整数Cij ,表示第i个人做第j件工作产生的效益为Cij .
输出格式
两行分别输出最小总效益和最大总效益。
输入输出样例
样例输入
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
样例输出
5 14
说明/提示
1≤ n≤100 一个人只能修一个工件
这是一道费用流经典题目
建图
1.设0为超级源点,2*n+1为超级汇点,第i个人的节点为i,第j件工作节点为j+n
2.从超级源点 向任意 i 属于[1,n] 连接一条容量为1,费用为0的边
3.从任意 j 属于 [n+1,2*n] 向超级汇点连接一条容量为1,费用为0的边
4.从任意 i 属于 [1,n]向 任意 j 属于 [n+1,n*2],连接一条容量为1,费用为Ci,j 的边
做法
跑一遍最小费用最大流&最大费用最小流,然后再分别输出最小值与最大值 (温馨提醒:一定要输出,不然会WA!)
为各位大佬献上我丑陋的代码~
1 #include<bits/stdc++.h> 2 #define FQ(i,a,b) for(register int i=a;i<=b;i++) 3 #define prf printf 4 #define scf scanf 5 #define ll long long 6 using namespace std; 7 const int N=5e4+10; 8 int INF,n,num=1,ne[N],fi[N],to[N],w[N],pl[N],S,T; 9 int dst[N],incf[N],P[N],vis[N],ans; 10 queue<int> q; 11 void FindMaxN() 12 { 13 int fINDmAXn[1]; 14 memset(fINDmAXn,128/2,sizeof(fINDmAXn)); 15 INF=fINDmAXn[0]; 16 } 17 ll read() 18 { 19 ll x=0,f=1;char ch=getchar(); 20 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 21 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 22 return x*f; 23 } 24 void add(int x,int y,int z,int kl) 25 { 26 ne[++num]=fi[x]; 27 fi[x]=num; 28 to[num]=y; 29 w[num]=z; 30 pl[num]=kl; 31 } 32 bool spfa() 33 { 34 for(int i=S;i<=T;i++)dst[i]=INF; 35 memset(vis,0,sizeof(vis)); 36 q.push(S),dst[S]=0; 37 incf[S]=1<<30,vis[S]=true; 38 while(!q.empty()) 39 { 40 int x=q.front(); 41 vis[x]=false;q.pop(); 42 for(int i=fi[x];i;i=ne[i]) 43 { 44 int ver=to[i]; 45 if(dst[ver]>dst[x]+pl[i]&&w[i]) 46 { 47 dst[ver]=dst[x]+pl[i]; 48 incf[ver]=min(incf[x],w[i]); 49 P[ver]=i; 50 if(!vis[ver])vis[ver]=true,q.push(ver); 51 } 52 } 53 } 54 return dst[T]!=INF; 55 } 56 void update() 57 { 58 int x=T; 59 while(x!=S) 60 { 61 int i=P[x]; 62 w[i]-=incf[T]; 63 w[i^1]+=incf[T]; 64 65 x=to[i^1]; 66 } 67 ans+=dst[T]*incf[T]; 68 } 69 bool spfa_d() 70 { 71 for(int i=S;i<=T;i++)dst[i]=-INF; 72 q.push(S),dst[S]=0;incf[S]=1<<30; 73 while(!q.empty()) 74 { 75 int x=q.front(); 76 vis[x]=false;q.pop(); 77 for(int i=fi[x];i;i=ne[i]) 78 { 79 int ver=to[i]; 80 if(dst[ver]<dst[x]+pl[i]&&w[i]) 81 { 82 dst[ver]=dst[x]+pl[i]; 83 incf[ver]=min(incf[x],w[i]); 84 P[ver]=i; 85 if(!vis[ver])vis[ver]=true,q.push(ver); 86 } 87 } 88 } 89 return dst[T]!=-INF; 90 } 91 void update_d() 92 { 93 int x=T; 94 while(x!=S) 95 { 96 int i=P[x]; 97 w[i]-=incf[T]; 98 w[i^1]+=incf[T]; 99 x=to[i^1]; 100 } 101 ans+=dst[T]*incf[T]; 102 } 103 void add_x(int x,int y,int z,int kl) 104 { 105 add(x,y,z,kl); 106 add(y,x,0,-kl); 107 } 108 int main() 109 { 110 //freopen(".in","r",stdin); 111 //freopen(".out","w",stdout); 112 FindMaxN(); 113 n=read();S=0,T=n*2+1; 114 for(int i=1;i<=n;i++) 115 { 116 for(int j=1;j<=n;j++) 117 { 118 int x=read(); 119 add_x(i,j+n,1,x); 120 } 121 } 122 for(int i=1;i<=n;i++)add_x(S,i,1,0),add_x(i+n,T,1,0); 123 while(spfa())update(); 124 printf("%d\n",ans); 125 ans=0; 126 for(int i=2;i<=num;i+=2)w[i]+=w[i^1],w[i^1]=0; 127 while(spfa_d())update_d(); 128 printf("%d\n",ans); 129 return 0; 130 } 131 //**月雩·薇嫭**
by:月雩·薇嫭