poj 2195 二分图带权匹配+最小费用最大流

题意:有一个矩阵,某些格有人,某些格有房子,每个人可以上下左右移动,问给每个人进一个房子,所有人需要走的距离之和最小是多少。

貌似以前见过很多这样类似的题,都不会,现在知道是用KM算法做了

KM算法目前还没弄懂,先套模板做

 

Sample Input

2 2

.m

H.

5 5

HH..m

.....

.....

.....

mm..H

7 8

...H....

...H....

...H....

mmmHmmmm

...H....

...H....

...H....

0 0

Sample Output

2

10

28



  1 #include<stdio.h>

  2 #include<iostream>

  3 #include<string.h>

  4 #include<algorithm>

  5 #include<math.h>

  6 using namespace std;

  7 const int MAXN=120;

  8 const int INF=0x3fffffff;

  9 int g[MAXN][MAXN],match1[MAXN],match2[MAXN];

 10 int KM(int m,int n)

 11 {

 12     int i,j,k,p,q;

 13     int l1[MAXN],l2[MAXN];

 14     int s[MAXN],t[MAXN];

 15     int ret=0;

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

 17     {

 18         l1[i]=-INF;

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

 20           if(g[i][j]>l1[i])

 21              l1[i]=g[i][j];

 22         if(l1[i]==-INF) return -1;//无法匹配

 23     }

 24     for(i=0;i<n;i++)l2[i]=0;

 25 

 26     memset(match1,-1,sizeof(match1));

 27     memset(match2,-1,sizeof(match2));

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

 29     {

 30         memset(t,-1,sizeof(t));

 31         for(s[p=q=0]=i;p<=q&&match1[i]<0;p++)

 32             for(k=s[p],j=0;j<n&&match1[i]<0;j++)

 33                 if(l1[k]+l2[j]==g[k][j]&&t[j]<0)

 34                 {

 35                     s[++q]=match2[j],t[j]=k;

 36                     if(s[q]<0)

 37                       for(p=j;p>=0;j=p)

 38                          match2[j]=k=t[j],p=match1[k],match1[k]=j;

 39                 }

 40 

 41         if(match1[i]<0)

 42         {

 43             for(i--,p=INF,k=0;k<=q;k++)

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

 45                  if(t[j]<0&&l1[s[k]]+l2[j]-g[s[k]][j]<p)

 46                      p=l1[s[k]]+l2[j]-g[s[k]][j];

 47 

 48 

 49             for(j=0;j<n;j++)if(t[j]>=0)l2[j]+=p;

 50             for(k=0;k<=q;k++)l1[s[k]]-=p;

 51         }

 52     }

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

 54     {

 55         if(match1[i]<0)return -1;//无法匹配

 56         if(g[i][match1[i]]<=-INF)return -1;

 57         ret+=g[i][match1[i]];

 58     }

 59     return ret;

 60 }

 61 struct Node

 62 {

 63     int x,y;

 64 };

 65 Node node1[MAXN],node2[MAXN];

 66 char str[MAXN];

 67 int main()

 68 {

 69     int n,m;

 70     int nx,ny;

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

 72     {

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

 74         nx=0;

 75         ny=0;

 76         for(int i=0;i<n;i++)

 77         {

 78             scanf("%s",&str);

 79             for(int j=0;j<m;j++)

 80             {

 81                 if(str[j]=='m')

 82                 {

 83                     node1[nx].x=i;

 84                     node1[nx].y=j;

 85                     nx++;

 86                 }

 87                 else if(str[j]=='H')

 88                 {

 89                     node2[ny].x=i;

 90                     node2[ny].y=j;

 91                     ny++;

 92                 }

 93             }

 94         }

 95         for(int i=0;i<nx;i++)

 96         for(int j=0;j<ny;j++)

 97         {

 98             g[i][j]=-abs(node1[i].x-node2[j].x)-abs(node1[i].y-node2[j].y);

 99         }

100         printf("%d\n",-KM(nx,ny));

101     }

102     return 0;

103 }

 

  1 /*

  2 POJ 2195 Going Home

  3 邻接矩阵形式最小费用最大流

  4 */

  5 

  6 #include<stdio.h>

  7 #include<iostream>

  8 #include<algorithm>

  9 #include<string.h>

 10 #include<queue>

 11 using namespace std;

 12 

 13 

 14 //************************************************************

 15 //最小费用最大流算法

 16 //SPFA求最短路

 17 //邻接矩阵形式

 18 //初始化:cap:容量,没有边为0

 19 //cost:耗费,对称形式,没有边的也为0

 20 //c是最小费用

 21 //f是最大流

 22 //*******************************************************

 23 const int MAXN=500;

 24 const int INF=0x3fffffff;

 25 int cap[MAXN][MAXN];//容量,没有边为0

 26 int flow[MAXN][MAXN];

 27 //耗费矩阵是对称的,有i到j的费用,则j到i的费用为其相反数

 28 int cost[MAXN][MAXN];

 29 

 30 

 31 int n;//顶点数目0~n-1

 32 int f;//最大流

 33 int c;//最小费用

 34 int start,end;//源点和汇点

 35 

 36 bool vis[MAXN];//在队列标志

 37 int que[MAXN];

 38 int pre[MAXN];

 39 int dist[MAXN];//s-t路径最小耗费

 40 bool SPFA()

 41 {

 42     int front=0,rear=0;

 43     for(int u=0;u<=n;u++)

 44     {

 45         if(u==start)

 46         {

 47             que[rear++]=u;

 48             dist[u]=0;

 49             vis[u]=true;

 50         }

 51         else

 52         {

 53             dist[u]=INF;

 54             vis[u]=false;

 55         }

 56     }

 57     while(front!=rear)

 58     {

 59         int u=que[front++];

 60         vis[u]=false;

 61         if(front>=MAXN)front=0;

 62         for(int v=0;v<=n;v++)

 63         {

 64             if(cap[u][v]>flow[u][v]&&dist[v]>dist[u]+cost[u][v])

 65             {

 66                 dist[v]=dist[u]+cost[u][v];

 67                 pre[v]=u;

 68                 if(!vis[v])

 69                 {

 70                     vis[v]=true;

 71                     que[rear++]=v;

 72                     if(rear>=MAXN)rear=0;

 73                 }

 74             }

 75         }

 76     }

 77     if(dist[end]>=INF)return false;

 78     return true;

 79 }

 80 

 81 void minCostMaxflow()

 82 {

 83     memset(flow,0,sizeof(flow));

 84     c=f=0;

 85     while(SPFA())

 86     {

 87         int Min=INF;

 88         for(int u=end;u!=start;u=pre[u])

 89            Min=min(Min,cap[pre[u]][u]-flow[pre[u]][u]);

 90         for(int u=end;u!=start;u=pre[u])

 91         {

 92             flow[pre[u]][u]+=Min;

 93             flow[u][pre[u]]-=Min;

 94         }

 95         c+=dist[end]*Min;

 96         f+=Min;

 97     }

 98 }

 99 //************************************************************

100 

101 struct Node

102 {

103     int x,y;

104 };

105 Node node1[MAXN],node2[MAXN];

106 char str[MAXN][MAXN];

107 int main()

108 {

109     //freopen("in.txt","r",stdin);

110     //freopen("out.txt","w",stdout);

111     int N,M;

112     while(scanf("%d%d",&N,&M))

113     {

114         if(N==0&&M==0)break;

115         int tol1=0,tol2=0;

116         for(int i=0;i<N;i++)

117         {

118             scanf("%s",&str[i]);

119             for(int j=0;j<M;j++)

120             {

121                 if(str[i][j]=='m')

122                 {

123                     tol1++;

124                     node1[tol1].x=i;

125                     node1[tol1].y=j;

126                 }

127                 else if(str[i][j]=='H')

128                 {

129                     tol2++;

130                     node2[tol2].x=i;

131                     node2[tol2].y=j;

132                 }

133             }

134         }

135         start=0;

136         n=tol1+tol2+1;

137         end=tol1+tol2+1;

138         memset(cap,0,sizeof(cap));

139         memset(cost,0,sizeof(cost));

140         for(int i=1;i<=tol1;i++)

141         {

142             cost[0][i]=cost[i][0]=0;

143             cap[0][i]=1;

144         }

145         for(int i=1;i<=tol2;i++)

146         {

147             cost[tol1+i][end]=0;

148             cap[tol1+i][end]=1;

149         }

150         for(int i=1;i<=tol1;i++)

151           for(int j=1;j<=tol2;j++)

152           {

153               cost[i][tol1+j]=abs(node1[i].x-node2[j].x)+abs(node1[i].y-node2[j].y);

154               cost[tol1+j][i]=-cost[i][tol1+j];

155               cap[i][tol1+j]=1;

156           }

157         minCostMaxflow();

158         printf("%d\n",c);

159     }

160     return 0;

161 }

 

  1 /*

  2 POJ 2195 Going Home

  3 邻接表形式最小费用最大流

  4 */

  5 

  6 #include<stdio.h>

  7 #include<iostream>

  8 #include<algorithm>

  9 #include<string.h>

 10 #include<queue>

 11 using namespace std;

 12 

 13 const int MAXN=1000;

 14 const int MAXE=100000;

 15 const int INF=0x3f3f3f3f;

 16 struct Edge

 17 {

 18     int from;

 19     int to;

 20     int next;

 21     int re;//记录逆边的下标

 22     int cap;//容量

 23     int cost;//费用

 24 }edge[MAXE];

 25 int pre[MAXN];

 26 int head[MAXN];

 27 bool vis[MAXN];

 28 int que[MAXN];

 29 int dist[MAXN];

 30 int tol;//边的总数

 31 void add(int u,int v,int ca,int co)

 32 {

 33     edge[tol].from=u;

 34     edge[tol].to=v;

 35     edge[tol].cap=ca;

 36     edge[tol].cost=co;

 37     edge[tol].re=tol+1;

 38     edge[tol].next=head[u];

 39     head[u]=tol++;

 40 

 41     edge[tol].from=v;//加逆边

 42     edge[tol].to=u;

 43     edge[tol].cap=0;

 44     edge[tol].cost=-co;

 45     edge[tol].re=tol-1;

 46     edge[tol].next=head[v];

 47     head[v]=tol++;

 48 }

 49 int n;

 50 int start;

 51 int end;

 52 bool SPFA()

 53 {

 54     int front=0,rear=0;

 55     for(int v=0;v<=n;v++)

 56     {

 57         if(v==start)

 58         {

 59             que[rear++]=v;

 60             vis[v]=true;

 61             dist[v]=0;

 62         }

 63         else

 64         {

 65             dist[v]=INF;

 66             vis[v]=false;

 67         }

 68     }

 69     while(front!=rear)

 70     {

 71         int u=que[front++];

 72         vis[u]=false;

 73         if(front>=MAXN)front=0;

 74         for(int i=head[u];i!=-1;i=edge[i].next)

 75         {

 76             int v=edge[i].to;

 77             if(edge[i].cap&&dist[v]>dist[u]+edge[i].cost)

 78             {

 79                 dist[v]=dist[u]+edge[i].cost;

 80                 pre[v]=i;

 81                 if(!vis[v])

 82                 {

 83                     que[rear++]=v;

 84                     vis[v]=true;

 85                     if(rear>=MAXN)rear=0;

 86                 }

 87             }

 88         }

 89     }

 90     if(dist[end]==INF)return false;

 91     return true;

 92 }

 93 int c;//费用

 94 int f;//最大流

 95 

 96 void minCostMaxflow()

 97 {

 98     c=f=0;

 99     int u,p;

100     while(SPFA())

101     {

102         int Min=INF;

103         for(u=end;u!=start;u=edge[p].from)

104         {

105             p=pre[u];

106             Min=min(Min,edge[p].cap);

107         }

108         for(u=end;u!=start;u=edge[p].from)

109         {

110             p=pre[u];

111             edge[p].cap-=Min;

112             edge[edge[p].re].cap+=Min;

113 

114         }

115         c+=dist[end]*Min;

116         f+=Min;

117     }

118 }

119 

120 

121 struct Node

122 {

123     int x,y;

124 };

125 Node node1[MAXN],node2[MAXN];

126 char str[MAXN][MAXN];

127 int main()

128 {

129    // freopen("in.txt","r",stdin);

130     //freopen("out.txt","w",stdout);

131     int N,M;

132     while(scanf("%d%d",&N,&M))

133     {

134         if(N==0&&M==0)break;

135         int tol1=0,tol2=0;

136         for(int i=0;i<N;i++)

137         {

138             scanf("%s",&str[i]);

139             for(int j=0;j<M;j++)

140             {

141                 if(str[i][j]=='m')

142                 {

143                     tol1++;

144                     node1[tol1].x=i;

145                     node1[tol1].y=j;

146                 }

147                 else if(str[i][j]=='H')

148                 {

149                     tol2++;

150                     node2[tol2].x=i;

151                     node2[tol2].y=j;

152                 }

153             }

154         }

155         start=0;

156         n=tol1+tol2+1;

157         end=tol1+tol2+1;

158 

159         //加边之前一定要初始化

160         tol=0;//边数

161         memset(head,-1,sizeof(head));//一定要初始化为-1

162 

163 

164         for(int i=1;i<=tol1;i++)

165         {

166             add(0,i,1,0);

167         }

168         for(int i=1;i<=tol2;i++)

169         {

170             add(tol1+i,end,1,0);

171         }

172         for(int i=1;i<=tol1;i++)

173           for(int j=1;j<=tol2;j++)

174           {

175               int temp=abs(node1[i].x-node2[j].x)+abs(node1[i].y-node2[j].y);

176               add(i,tol1+j,1,temp);

177           }

178         minCostMaxflow();

179         printf("%d\n",c);

180     }

181     return 0;

182 }

 

你可能感兴趣的:(poj)