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 }

时间: 2024-11-05 18:44:50

poj2195 bfs+最小权匹配的相关文章

POJ 3686 The Windy&#39;s【最小权匹配(神建图啊)】

大意:有n个任务m个机器,告诉你n*m的矩阵表示每个任务在每个机器上完成需要的时间 问所有任务完成的总时间最少?(比如第一个任务在第一分钟完成第二个任务在第二分钟完成   则总时间为1 + 2 = 3 分析: 该题自己做的时候没有思路 后来在网上搜题解,感觉建图真是太厉害了 假设最优情况下,个个任务需要的时间分别为a1, a2, a3, ……,an 那么总时间t = n * a1 + (n - 1) * a2 + ……+ 2 * an - 1 + an 也就是说只需要考虑系数就可以了 我们先假设

poj3565Ants【最小权匹配】

大意: 左图为一个坐标轴上的点  其中黑点代表ants 白点代表apple 问怎样安排ants匹配apple才能使人一两条边不想交 分析: 如左图,我们假设a->d,b->c为一个最佳匹配  交点为e 那么ad+bc = ae+ ed + be + ec = (ae + ec) + (be + ed)  该值大于ac+bd 所以匹配为最佳匹配不成立 因此我们只要求出二分图的最小匹配就是结果了 但是wa了: wa的代码: 1 #include <iostream> 2 #includ

poj 2195 Going Home 二分图最小权匹配KM算法

题意: 有n个人要回到n间房子里,每间房子只允许一个人,求n个人要走的最小距离和. 分析: 裸的二分图最小权匹配,KM搞之. 代码: //poj 2195 //sep9 #include <iostream> using namespace std; const int maxN=128; char g[maxN][maxN]; int mx[maxN],my[maxN],hx[maxN],hy[maxN]; int w[maxN][maxN]; int lx[maxN],ly[maxN],l

ural 1076 KM求最小权匹配

贴模板~ KM算法引进了顶标函数,不断缩小这个顶标来让相等子图的可能范围扩大 #include<iostream> #include<cstring> //KM 复杂度O^3 using namespace std; const int N=200; int lx[N],ly[N];//顶标函数 int w[N][N];//图 bool vix[N],viy[N]; int linky[N];// int lack;//每次顶标函数扩大的增量 int n,m; bool find(

二分图最佳匹配,求最大权匹配或最小权匹配

Beloved Sons http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1338 题意:国王有N个儿子,现在每个儿子结婚都能够获得一定的喜悦值,王子编号为1-N,有N个女孩的编号同样为1-N,每个王子心中都有心仪的女孩,现在问如果安排,能够使得题中给定的式子和最大. 分析:其实题目中那个开根号是个烟雾弹,只要关心喜悦值的平方即可.那么对王子和女孩之间构边,边权为喜悦值的平方,对于每一个王子虚拟出一个女孩边权为0,这样是为了所

POJ 2195 二分图最小权匹配KM算法

本来是打算昨天晚上写的, 昨天网速渣的连CSDN都进不去,没办法 只能现在来写了 先写写对KM算法的理解,KM算法是对每个点设置一个顶标,只有当边长等于两边点的顶标之和的时候才进行增广,这样就能保证得到的一定是最大权匹配. 如果找不到匹配的时候就对交替路中X集合的顶标减少一个d Y集合的顶标增加一个d. 这样两个点都在交替路中的时候x[i]+y[i]的和不边 X在 Y不在的时候x[i]+y[i]减少,可能就会为图增加一对匹配. X不在Y在的时候x[i]+y[i]增加, 原来不在现在依然不在其中.

【POJ 2400】 Supervisor, Supervisee(KM求最小权匹配)

[POJ 2400] Supervisor, Supervisee(KM求最小权匹配) Supervisor, Supervisee Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 2538   Accepted: 719 Description Suppose some supervisors each get to hire a new person for their department. There are N

[ACM] POJ 3686 The Windy&#39;s (二分图最小权匹配,KM算法,特殊建图)

The Windy's Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 4158   Accepted: 1777 Description The Windy's is a world famous toy factory that owns M top-class workshop to make toys. This year the manager receivesN orders for toys. The man

【POJ 2195】 Going Home(KM算法求最小权匹配)

[POJ 2195] Going Home(KM算法求最小权匹配) Going Home Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 20303   Accepted: 10297 Description On a grid map there are n little men and n houses. In each unit time, every little man can move one unit ste