题意:一个n*n的矩阵每个格子里有一个正整数w(i,j)你的任务是确定每行一个整数row(i)每列一个整数col(i),对每个格子都有w(i,j)<=row(i)+col(j)所有row(i)和col(i)和尽量小。
思路:本题利用KM算法l(x)+l(y)>=w(x,y)的性质直接可以知道得出的顶标之和即为最小的。
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> const int INF=0x3f3f3f3f; using namespace std; int s[505][505],visx[505],visy[505],match[505]; int lx[505],ly[505]; int n,m; int hungarian(int x){ int i; visx[x]=1; for(i=1;i<=m;i++){ if(!visy[i]&&lx[x]+ly[i]==s[x][i]){ visy[i]=1; if(!match[i]||hungarian(match[i])){ match[i]=x; return 1; } } } return 0; } int KM(){ int i,j,k,sum,temp; sum=0; memset(lx,0,sizeof(lx)); memset(ly,0,sizeof(ly)); memset(match,0,sizeof(match)); for(i=1;i<=n;i++) for(j=1;j<=m;j++) lx[i]=max(lx[i],s[i][j]); for(i=1;i<=n;i++){ while(1){ memset(visx,0,sizeof(visx)); memset(visy,0,sizeof(visy)); if(hungarian(i)) break; else{ temp=INF; for(j=1;j<=n;j++) if(visx[j]){ for(k=1;k<=m;k++) if(!visy[k]) temp=min(temp,lx[j]+ly[k]-s[j][k]); } if(temp==INF) return -1; for(j=1;j<=n;j++) if(visx[j]) lx[j]-=temp; for(j=1;j<=m;j++) if(visy[j]) ly[j]+=temp; } } } for(i=1;i<=m;i++) if(match[i]!=0){ if(s[match[i]][i]!=-INF) sum+=s[match[i]][i]; else return -1; } return sum; } int main(){ int i,j,a,b,c,ans,num; while(scanf("%d",&n)!=EOF){ m=n; for(i=1;i<=n;i++) for(j=1;j<=m;j++) s[i][j]=-INF; for(i=1;i<=n;i++) for(j=1;j<=m;j++){ scanf("%d",&num); s[i][j]=num; } ans=KM(); for(i=1;i<=n;i++) printf("%d ",lx[i]); printf("\n"); for(i=1;i<=m;i++) printf("%d ",ly[i]); printf("\n"); printf("%d\n",ans); } return 0; }
时间: 2024-11-06 07:35:58