题目描述
有 nn 件工作要分配给 n 个人做。第 i 个人做第 j 件工作产生的效益为 cij。试设计一个将 n 件工作分配给 n 个人做的分配方案,使产生的总效益最大。
题解:
第一反应裸的二分图最优匹配
最小总效益就是把边取负值求最大总效益即可
网络流也可以做,先将源点S与每个人连一条容量为1,费用为0的弧,同样从每一个任务向汇点连一条容量为1,费用为0的弧
然后对于每一个人和每一个任务,对应的从人向任务连一条容量为1,费用为Cij的弧,然后跑最大费用最大流和最小费用最大流就行了
为什么要标记容量为1,因为设置容量是为了防止一个点被多次匹配
代码都不是自己的,等日后有空补上
代码:
第一个方法:
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<cstdlib> #include<string> #include<queue> #include<map> #include<vector> #include<ctime> #define ll long long #define R register #define IL inline #define Rf(a,b,c) for(R int (a)=(b);(a)<=(c);++(a)) #define Tf(a,b,c) for(R int (a)=(b);(a)>=(c);--(a)) #define MP make_pair #define PA pair<int,int> #define MES(a,b) memset((a),(b),sizeof((a))) #define MEC(a,b) memset((a),(b),sizeof((b))) #define D double using namespace std; const int N=505; int n,m,lx[N],ly[N],link[N],w[N][N]; bool S[N],T[N]; IL int read() { int x=0,f=1;char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x*=10;x+=(ch-'0');ch=getchar();} return x*f; } IL void write(int x) { if(x<0) putchar('-'),x=-x; if(x>9) write(x/10); putchar(x%10+'0'); } bool dfs(int x) {//这就是一般的二分图匹配 S[x]=true;//把左边的点都加入S Rf(i,1,n) if(lx[x]+ly[i]==w[x][i]&&!T[i]) {//判断这条边是否在相等子图里,不要再建图了 T[i]=true;//右边的点加入T if(!link[i]||dfs(link[i])) { link[i]=x; return true; } } return false; } IL void update() {//n^2暴力找a,并修改 R int a=1<<30; Rf(i,1,n) if(S[i]) Rf(j,1,n) if(!T[j]) a=min(a,lx[i]+ly[j]-w[i][j]); Rf(i,1,n) { if(S[i]) lx[i]-=a; if(T[i]) ly[i]+=a; } } IL void KM() { Rf(i,1,n) { link[i]=lx[i]=ly[i]=0; Rf(j,1,n) lx[i]=max(lx[i],w[i][j]);//顶标初值 } Rf(i,1,n) while(true) { Rf(j,1,n) S[j]=T[j]=false;//记得每次都要清空 if(dfs(i)) break;//找到增广路了 else update();//没找到就得松弛了 } } signed main() { n=read(); Rf(i,1,n) Rf(j,1,n) w[i][j]=read(); KM(); int sum1=0,sum2=0; Rf(i,1,n) sum1+=lx[i]+ly[i];//最后的顶标和就是最终答案了 Rf(i,1,n) Rf(j,1,n) w[i][j]*=-1;//整体取负跑最小 KM(); Rf(i,1,n) sum2+=lx[i]+ly[i]; write(-sum2);//记得要把答案再取负回来啊 putchar('\n');write(sum1); return 0; }
第二个方法:
#include<bits/stdc++.h> #define FQ(i,a,b) for(register int i=a;i<=b;i++) #define prf printf #define scf scanf #define ll long long using namespace std; const int N=5e4+10; int INF,n,num=1,ne[N],fi[N],to[N],w[N],pl[N],S,T; int dst[N],incf[N],P[N],vis[N],ans; queue<int> q; void FindMaxN() { int fINDmAXn[1]; memset(fINDmAXn,128/2,sizeof(fINDmAXn)); INF=fINDmAXn[0]; } ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } void add(int x,int y,int z,int kl) { ne[++num]=fi[x]; fi[x]=num; to[num]=y; w[num]=z; pl[num]=kl; } bool spfa() { for(int i=S;i<=T;i++)dst[i]=INF; memset(vis,0,sizeof(vis)); q.push(S),dst[S]=0; incf[S]=1<<30,vis[S]=true; while(!q.empty()) { int x=q.front(); vis[x]=false;q.pop(); for(int i=fi[x];i;i=ne[i]) { int ver=to[i]; if(dst[ver]>dst[x]+pl[i]&&w[i]) { dst[ver]=dst[x]+pl[i]; incf[ver]=min(incf[x],w[i]); P[ver]=i; if(!vis[ver])vis[ver]=true,q.push(ver); } } } return dst[T]!=INF; } void update() { int x=T; while(x!=S) { int i=P[x]; w[i]-=incf[T]; w[i^1]+=incf[T]; x=to[i^1]; } ans+=dst[T]*incf[T]; } bool spfa_d() { for(int i=S;i<=T;i++)dst[i]=-INF; q.push(S),dst[S]=0;incf[S]=1<<30; while(!q.empty()) { int x=q.front(); vis[x]=false;q.pop(); for(int i=fi[x];i;i=ne[i]) { int ver=to[i]; if(dst[ver]<dst[x]+pl[i]&&w[i]) { dst[ver]=dst[x]+pl[i]; incf[ver]=min(incf[x],w[i]); P[ver]=i; if(!vis[ver])vis[ver]=true,q.push(ver); } } } return dst[T]!=-INF; } void update_d() { int x=T; while(x!=S) { int i=P[x]; w[i]-=incf[T]; w[i^1]+=incf[T]; x=to[i^1]; } ans+=dst[T]*incf[T]; } void add_x(int x,int y,int z,int kl) { add(x,y,z,kl); add(y,x,0,-kl); } int main() { //freopen(".in","r",stdin); //freopen(".out","w",stdout); FindMaxN(); n=read();S=0,T=n*2+1; for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { int x=read(); add_x(i,j+n,1,x); } } for(int i=1;i<=n;i++)add_x(S,i,1,0),add_x(i+n,T,1,0); while(spfa())update(); printf("%d\n",ans); ans=0; for(int i=2;i<=num;i+=2)w[i]+=w[i^1],w[i^1]=0; while(spfa_d())update_d(); printf("%d\n",ans); return 0; }