刘汝佳新书---训练指南
题意:给定一个N*N矩阵,每个格子里都有一个正整数w[i][j]。你的任务是给每行确定一个整数row[i],每列确定一个整数col[i],使得对于任意格子(i,j),w[i][j]《=row[i]+col[j]。所有row[i]和col[i]之和应尽量小。
分析:这题是KM算法的一个副产品,KM算法有等式l(x)+l(y)>=w(x,y).
// File Name: 11383.cpp // Author: zlbing // Created Time: 2013/2/27 23:37:40 #include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include<cmath> #include<queue> using namespace std; #define CL(x,v); memset(x,v,sizeof(x)); #define INF 0x3f3f3f3f #define MAXN 500+5 int Left[MAXN]; int w[MAXN][MAXN]; int Lx[MAXN],Ly[MAXN]; bool S[MAXN],T[MAXN]; int N; bool match(int i) { S[i]=true; for(int j=1;j<=N;j++)if(Lx[i]+Ly[j]==w[i][j]&&!T[j]) { T[j]=true; if(Left[j]==0||match(Left[j])) { Left[j]=i; return true; } } return false; } void update(){ int a=INF; for(int i=1;i<=N;i++)if(S[i]) for(int j=1;j<=N;j++)if(!T[j]) a=min(a,Lx[i]+Ly[j]-w[i][j]); for(int i=1;i<=N;i++){ if(S[i])Lx[i]-=a; if(T[i])Ly[i]+=a; } } void KM() { for(int i=1;i<=N;i++){ Left[i]=Lx[i]=Ly[i]=0; for(int j=1;j<=N;j++) { Lx[i]=max(Lx[i],w[i][j]); } } for(int i=1;i<=N;i++){ for(;;){ CL(S,0); CL(T,0); if(match(i))break; else update(); } } } int main(){ while(~scanf("%d",&N)) { for(int i=1;i<=N;i++) for(int j=1;j<=N;j++) scanf("%d",&w[i][j]); KM(); for(int i=1;i<=N;i++) if(i==1)printf("%d",Lx[i]); else printf(" %d",Lx[i]); printf("\n"); for(int i=1;i<=N;i++) if(i==1)printf("%d",Ly[i]); else printf(" %d",Ly[i]); printf("\n"); int sum=0; for(int i=1;i<=N;i++) sum+=Lx[i]+Ly[i]; printf("%d\n",sum); } return 0; }