poj2195_KM最小权值和

这道题的题意是:在一个矩阵空间中,分布着m个人和m个房子,每个房子中要安排一个人,每个人移动一步需要1美元,求为每个人安排房子后所需要的金钱的最小值。

分析:这道题乍一看是二分图匹配(还可以用网络流做,现在还不会啊),但是我们学过的KM算法求的是权值最大的匹配,这里求的是权值最小的匹配。怎么办呢?昨天学习了KM算法,如果对原理熟悉的话,其实最大权值和最小权值的道理一样。

KM最小权值和算法的原理:

1.顶点集分为A,B两个集合,初始化顶标Ai为与Ai相连的边的最小权值,Bi为0.在算法的整个过程中,保证Wij>=Ai+Bi。

2.相等子图:如果二分图的某个子图中每条匹配满足Wij=Ai+Bj,那个这个子图就是相等子图。如果相等子图中存在完美匹配的话,这个相等子图中的权值和即为最小权值和。

这个定理的证明:在整个算法的过程中,就是通过修改顶标找寻Wij=Ai+Bj的匹配,直到图中所有的匹配都满足这一条件,而一开始Wij>=Ai+Bj,所以算法结束后Wij之和具有最小的权值。

3.当某次找寻增广路失败时,此时找到的是一颗交错树,交错树的叶子都在A集合中,我们需要更新顶标值,让交错树A集合中的点加上d(这里与最大权值相反),对应B集合中的点减去d,这样可以让交错树A集合中的某些点形成Wij=Ai+Bj的情况,从而得到匹配。

4.每次的d是此次遍历过程中的Min{Wij-Ai-Bj}.

在这道题中,也没有必要存储结构,只需要将人和房子的坐标记录下来即可,然后建图。

以下是代码,昨晚写的,那个把j写成i的错误不能忍啊!!!

View Code
  1 #include <iostream>

  2 #include <memory.h>

  3 #include <stdio.h>

  4 #include <math.h>

  5 #include <stdlib.h>

  6 using namespace std;

  7 const int maxnum=999999;

  8 typedef struct

  9 {

 10     int x;

 11     int y;

 12 }rr;

 13 rr man[101],house[101];

 14 

 15 int array[101][101];

 16 int res[101];

 17 int muse[101];

 18 int huse[101];

 19 int mvalue[101];

 20 int hvalue[101];

 21 int v,d;

 22 

 23 bool find(int i)

 24 {

 25     muse[i]=true;

 26     int j;

 27     for(j=1;j<=v;j++)

 28     {

 29         if(huse[j]) continue;

 30         if(array[i][j]==0) continue;

 31         int t=array[i][j]-mvalue[i]-hvalue[j];

 32         if(t==0)

 33         {

 34             huse[j]=true;

 35             if(res[j]==0 || find(res[j]))

 36             {

 37                 res[j]=i;

 38                 return true;

 39             }

 40         }

 41         else if(d>t)

 42             d=t;

 43     }

 44     return false;

 45 }

 46 

 47 int main()

 48 {

 49     int m,n,i,j;

 50     char ch;

 51     int result;

 52     int cntman,cnthouse;

 53 

 54     while(scanf("%d%d",&m,&n)!=EOF)

 55     {

 56         if(m==0 && n==0) break;

 57         memset(array,0,sizeof(array));

 58         memset(res,0,sizeof(res));

 59         cntman=1;

 60         cnthouse=1;

 61         result=0;

 62         getchar();

 63         for(i=0;i<m;i++)

 64         {

 65             for(j=0;j<n;j++)

 66             {

 67                 scanf("%c",&ch);

 68                 if(ch=='m')

 69                 {

 70                     man[cntman].x=i;

 71                     man[cntman].y=j;

 72                     cntman++;

 73                 }

 74                 else if(ch=='H')

 75                 {

 76                     house[cnthouse].x=i;

 77                     house[cnthouse].y=j;

 78                     cnthouse++;

 79                 }

 80             }

 81             if(j==n) getchar();

 82         }

 83 

 84         v=cntman-1;

 85         for(i=1;i<=v;i++)  //建图

 86         {

 87             for(j=1;j<=v;j++)

 88             {

 89                 int len=abs(man[i].x-house[j].x)+abs(man[i].y-house[j].y);

 90                 array[i][j]=len;

 91             }

 92         }

 93 

 94         for(i=1;i<=v;i++)

 95         {

 96             mvalue[i]=maxnum;

 97             hvalue[i]=0;

 98         }

 99 

100         for(i=1;i<=v;i++)

101             for(j=1;j<=v;j++)

102             {

103                 if(mvalue[i]>array[i][j])

104                     mvalue[i]=array[i][j];

105             }

106 

107 

108         for(i=1;i<=v;i++)

109         {

110             while(1)

111             {

112                 memset(muse,false,sizeof(muse));

113                 memset(huse,false,sizeof(huse));

114                 d=maxnum;

115                 if(find(i))

116                     break;

117                 for(j=1;j<=v;j++)  //!!!

118                 {

119                     if(muse[j])   //交错树中的叶子

120                         mvalue[j]+=d;

121 

122                     if(huse[j])    //交错树中B中的点

123                         hvalue[j]-=d;

124                 }

125             }

126         }

127 

128         for(i=1;i<=v;i++)

129             result+=array[res[i]][i];

130         printf("%d\n",result);

131     }

132 

133 

134     return 0;

135 }

这道题也是tju oj1636

 

 

你可能感兴趣的:(poj)