poj2195 bfs+最小权匹配

     题意:给个矩阵,矩阵里有一些人和房子(人数和房子数相等),一个人只进一个房子(可以路过房子而不进),每走一步花费1美金,求所有人都进入房子的最小花费,这是典型的二分图带权匹配问题。

     这题就是建图有点麻烦,但绝不抽象,直接用BFS遍历每个人到所有房子的距离,遍历出一个就拉一条人到房子有向边,建完图就是套模板了。

     注意:KM算法是求最大权匹配的,要求最小权就要把所有边取相反数,最后结果再取相反数,但这只能是完美匹配,不完美匹配还要变一些。

    

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<vector>
  4 #include<queue>
  5 #include<iostream>
  6 #define maxn 500
  7 
  8 using namespace std;
  9 
 10 
 11 char group[101][101];
 12 int index[101][101];
 13 struct pos
 14 {
 15     int x,y;
 16 }people[maxn],house[maxn];
 17 struct edge
 18 {
 19     int to,cap;
 20 };
 21 vector<edge> g[maxn];
 22 int a,b,sum_m,sum_h;
 23 
 24 const int mir[4][2]={{0,1},{0,-1},{1,0},{-1,0}};
 25 int vis[101][101];
 26 struct step
 27 {
 28     int x,y,s;
 29 };
 30 void init()
 31 {
 32     sum_m=sum_h=0;
 33     memset(people,0,sizeof(people));
 34     memset(house,0,sizeof(house));
 35     memset(index,0,sizeof(index));
 36     for(int i=0;i<maxn;i++)
 37         g[i].clear();
 38 }
 39 void add_edge(int from,int to,int cap)
 40 {
 41     g[from].push_back((edge){to,cap});
 42 }
 43 void bfs(int sx,int sy,int ex,int ey)
 44 {
 45     memset(vis,0,sizeof(vis));
 46     step now,next;
 47     queue<step> q;
 48     now.x=sx,now.y=sy,now.s=0;
 49     vis[sx][sy]=1;
 50     q.push(now);
 51     while(!q.empty())
 52     {
 53         now=q.front();
 54         q.pop();
 55         if(now.x==ex&&now.y==ey)
 56         {
 57             add_edge(index[sx][sy],index[now.x][now.y],~now.s+1);
 58             return;
 59         }
 60         for(int i=0;i<4;i++)
 61         {
 62             int x=now.x+mir[i][0];
 63             int y=now.y+mir[i][1];
 64             if(x>=0&&y>=0&&x<a&&y<b)
 65             {
 66                 if(!vis[x][y])
 67                 {
 68                     vis[x][y]=1;
 69                     next.x=x,next.y=y,next.s=now.s+1;
 70                     q.push(next);
 71                 }
 72             }
 73         }
 74     }
 75 }
 76 int x[maxn], y[maxn], link[maxn],sx[maxn], sy[maxn];
 77 int slack;
 78 int DFS(int t)
 79 {
 80     int i, tmp;
 81     sx[t] = 1;
 82     for (i = 0; i < g[t].size(); i++)
 83     {
 84         edge e=g[t][i];
 85         if (!sy[e.to])
 86         {
 87             tmp = x[t] + y[e.to] - e.cap;
 88             if (tmp == 0)
 89             {
 90                 sy[e.to] = 1;
 91                 if (link[e.to] == -1 || DFS(link[e.to]))
 92                 {
 93                     link[e.to] = t;
 94                     return 1;
 95                 }
 96             }
 97             else if (tmp < slack)
 98                 slack = tmp;
 99         }
100     }
101     return 0;
102 }
103 void KM()
104 {
105     int i, j;
106     for(int w=0;w<sum_m;w++)
107     {
108         x[w]=0;
109         for(int v=0;v<g[w].size();v++)
110         {
111             if(g[w][v].cap>x[w])
112                 x[w]=g[w][v].cap;
113         }
114     }
115     for (j = 0; j < sum_h; j++)
116     {
117         y[j] = 0;
118     }
119     memset(link, -1, sizeof(link));
120     for (i = 0; i < sum_m; i++)
121     {
122         while (1)
123         {
124             memset(sx, 0, sizeof(sx));
125             memset(sy, 0, sizeof(sy));
126             slack = 0xfffffff;
127             if (DFS(i)) break;
128             for (j = 0; j < sum_m; j++)
129             {
130                 if (sx[j])
131                     x[j] -= slack;
132             }
133             for (j = 0; j < sum_h; j++)
134             {
135                 if (sy[j])
136                     y[j] += slack;
137             }
138         }
139     }
140 }
141 
142 int main()
143 {
144     while(scanf("%d%d",&a,&b)!=EOF,a&&b)
145     {
146         getchar();
147         init();
148         for(int i=0;i<a;i++)
149         {
150             gets(group[i]);
151             for(int j=0;j<b;j++)
152             {
153                 if(group[i][j]=='m')
154                 {
155                     people[sum_m].x=i;
156                     people[sum_m].y=j;
157                     index[i][j]=sum_m;
158                     sum_m++;
159                 }
160                 else if(group[i][j]=='H')
161                 {
162                     house[sum_h].x=i;
163                     house[sum_h].y=j;
164                     index[i][j]=sum_h;
165                     sum_h++;
166                 }
167             }
168         }
169         for(int n=0;n<sum_m;n++)
170         {
171             for(int m=0;m<sum_h;m++)
172             {
173                 bfs(people[n].x,people[n].y,house[m].x,house[m].y);
174             }
175         }
176   /*     for(int i=0;i<sum_m;i++)
177         {
178             cout<<i<<" ";
179             for(int j=0;j<g[i].size();j++)
180                 cout<<g[i][j].to<<" "<<g[i][j].cap<<endl;
181         }*/
182         KM();
183         int ans=0;
184         int coun = 0,t=0;
185         for (int i = 0; i < sum_h; i++)
186         {
187             t = link[i];
188             if (t >= 0)
189             {
190                 coun ++;
191                 ans += g[t][i].cap;
192             }
193         }
194         printf("%d\n",~ans+1);
195     }
196     return 0;
197 }
View Code

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值