RPG girls今天和大家一起去游乐场玩,终于可以坐上梦寐以求的过山车了。可是,过山车的每一排只有两个座位,而且还有条不成文的规矩,就是每个女生必须找个个男生做partner和她同坐。但是,每个女孩都有各自的想法,举个例子把,Rabbit只愿意和XHD或PQK做partner,Grass只愿意和linle或LL做partner,PrincessSnow愿意和水域浪子或伪酷儿做partner。考虑到经费问题,boss刘决定只让找到partner的人去坐过山车,其他的人,嘿嘿,就站在下面看着吧。聪明的Acmer,你可以帮忙算算最多有多少对组合可以坐上过山车吗? |
输入数据的第一行是三个整数K , M , N,分别表示可能的组合数目,女生的人数,男生的人数。0<K<=1000 1<=N 和M<=500.接下来的K行,每行有两个数,分别表示女生Ai愿意和男生Bj做partner。最后一个0结束输入。 |
对于每组数据,输出一个整数,表示可以坐上过山车的最多组合数。 |
6 3 3 1 1 1 2 1 3 2 1 2 3 3 1 0 |
3 |
分析:
数据结构:
保存二分图用的是邻接表。
为方便存储和阅读,数组下标从1开始(0那个空间就空着不用)。
因此,第i个表头邻接的是第i个女生愿意与他做partner的男生号。
集合X、Y用一维数组表示。下标同样从1开始。
如果它们暂时没有点配对,则里面保存的是O,否则保存配对的点的下标。
初始状态X、Y都为0。
因为X是从1到n循环,所以只需要判断Y集合中的点是否被访问过。
判断是否被访问过用一个Bool型一维数组,true表示被访问过,false表示未被访问过。
中间记录增广路径用栈结构。因为增广路径的边数是奇数,根据握手定理,它的顶点数一定是偶数。
找到增广路径以后,每次从栈顶取出2个端点,就是现在相互配对的端点了。一直到栈取空为止。
算法实现:
实现匈牙利算法分为4个步骤:
- 初始化:
集合X、Y清空
图清空 - 输入:
输入集合X、Y的大小size_x和size_y,以及所有的边 - 计算:
i从1循环到size_x,深搜寻找Xi的增广路径
每次寻找前要先清空栈,并且初始Visit数组为false
在深搜的过程中,要注意,如果寻找增广路径失败,要记得把刚加入的那一个顶点从栈中删除
如果增广路径查找成功,就开始读栈,对X、Y里相互配对的端点进行标记,直到栈为空 - 输出:
统计X(Y)集合中有配对的端点个数,即最大匹配数。
输出最大匹配数
代码实现:
#include <stack>
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef struct node
{
int ord;
node * next;
}Node;
const int size = 512 + 1;
Node list[size];
int X[size];
int Y[size];
bool visit[size];
int size_x;
int size_y;
stack <int> stk;
void init()
{
int i;
for (i = 1; i <= size_x; i++)
list[i].next = NULL;
memset(X, 0, (size_x + 1) * sizeof(int));
memset(Y, 0, (size_y + 1) * sizeof(int));
}
void input(int len)
{
int i;
int x;
int y;
Node* p;
for (i = 0; i < len; i++)
{
scanf("%d%d", &x, &y);
p = new Node;
p->ord = y;
p->next = list[x].next;
list[x].next = p;
}
}
bool dfs(int x)
{
Node* p;
stk.push(x);
for (p = list[x].next; p; p = p->next)
{
if (!visit[p->ord])
{
visit[p->ord] = true;
stk.push(p->ord);
if (!Y[p->ord] || dfs(Y[p->ord]))
return true;
else
stk.pop();
}
}
stk.pop();
return false;
}
void solve()
{
int i;
int top;
for (i = 1; i <= size_x; i++)
{
while (!stk.empty()) stk.pop();
memset(visit, false, size_y + 1);
if (dfs(i))
{
while (!stk.empty())
{
top = stk.top();
stk.pop();
Y[top] = stk.top();
X[stk.top()] = top;
stk.pop();
}
}
}
}
void output()
{
int i;
int count = 0;
Node* p;
for (i = 1; i <= size_x; i++)
{
if (X[i]) count++;
while (p = list[i].next)
{
list[i].next = p->next;
delete p;
}
}
cout << count << endl;
}
int main(void)
{
int n;
while (scanf("%d", &n), n)
{
scanf("%d%d", &size_x, &size_y);
init();
input(n);
solve();
output();
while (!stk.empty()) stk.pop();
}
return 0;
}