题意:在一个N*N的方格中,各有一个整数w(i,j),现在要求给每行构造row(i),给每列构造col(j),使得任意w(i,j)<=row(i)+col(j),输出row(i)与col(j)之和最小的方案。
当看到w(i,j)<=row(i)+col(j),并且row()col()都是自己构造的时候,就想到了二分匹配:w[i,j]<=Lx[i]+Ly[j]。直接套用模板,求最佳二分完美匹配,输出Lx[],Ly[],以及最小值即可。
1 #include<cstdio> 2 #include<cstring> 3 #include<cmath> 4 #include<algorithm> 5 #define clr(a,m) memset(a,m,sizeof(a)) 6 #define rep(i,a,b) for(int i=a;i<=b;i++) 7 using namespace std; 8 9 const int MAXN=555; 10 const int INF =1e9; 11 const double eps=1e-10; 12 13 int gap[MAXN][MAXN]; 14 int Lx[MAXN],Ly[MAXN],slack[MAXN]; 15 int left[MAXN],n; 16 bool S[MAXN],T[MAXN]; 17 18 void read() 19 { 20 rep(i,1,n) 21 rep(j,1,n) 22 scanf("%d",&gap[i][j]); 23 } 24 25 bool match(int u) 26 { 27 S[u]=true; 28 rep(v,1,n) 29 if(!T[v]){ 30 int tmp=Lx[u]+Ly[v]-gap[u][v]; 31 if(tmp==0){ 32 T[v]=true; 33 if(!left[v]||match(left[v])){ 34 left[v]=u; 35 return true; 36 } 37 }else slack[v]=min(slack[v],tmp); 38 } 39 return false; 40 } 41 42 void update() 43 { 44 int a=INF; 45 rep(v,1,n) 46 if(!T[v]) 47 a=min(a,slack[v]); 48 rep(i,1,n){ 49 if(S[i])Lx[i]-=a; 50 if(T[i])Ly[i]+=a; 51 } 52 } 53 54 void KM() 55 { 56 rep(i,1,n){ 57 left[i]=Ly[i]=0; 58 Lx[i]=-INF; 59 rep(j,1,n) 60 Lx[i]=max(Lx[i],gap[i][j]); 61 } 62 rep(i,1,n){ 63 rep(j,1,n) 64 slack[j]=INF; 65 while(1) 66 { 67 rep(j,1,n) 68 S[j]=T[j]=0; 69 if(match(i)) 70 break; 71 else 72 update(); 73 } 74 } 75 } 76 77 void print() 78 { 79 int ans=0; 80 rep(i,1,n){ 81 ans+=Lx[i]; 82 if(i!=1)printf(" "); 83 printf("%d",Lx[i]); 84 85 } 86 printf(" "); 87 rep(i,1,n){ 88 ans+=Ly[i]; 89 if(i!=1)printf(" "); 90 printf("%d",Ly[i]); 91 } 92 printf(" "); 93 printf("%d ",ans); 94 } 95 96 int main() 97 { 98 while(~scanf("%d",&n)) 99 { 100 read(); 101 KM(); 102 print(); 103 } 104 return 0; 105 }