题目地址
我在做这道题时距离我写这篇博客已经有一个多月了,当时看到这道题,以为是贪心题,先让最少选择的先上,因为多选择意味着尽量多,现在仔细想了想,是错的,要看怎么错,可以这样想,如果不是最少选择的先上,会不会增加匹配数。
看了discuss,啊!匈牙利算法,厉害。
匈牙利算法博客
趣写算法
写一下基本概念增加印象。
交错路:从未匹配点出发,经过未匹配边,匹配边,未匹配边,匹配边…如此循环
增广路:走交错路,直到遇到第一个未匹配点,如果没有,说明找不到。如果找到了,匹配边增1。
看了基本概念,想要怎么样去实现算法。
首先要解决的第一个问题,如何储存一个图,(因为是第一道遇到的图论题,即便已经学过邻接矩阵,也是没想到用矩阵来存储,所以竟然傻的用一个结构来表示边,每一个结构是一条边,然后有它连接的两点x,y,实在太傻逼了,实在是难处理,又傻又难处理。
回到用邻接矩阵来储存,开了个二维数组,然后顺利存储。
第二个问题,找非匹配点时,如何转移扫描,又想了好久,发现用了一数组来存储匹配点的另一个点,然后通过数组来进行下一步的递归。
第三个问题,如何防止自己找到自己,一个bool数组,就可以。
贴上代码
#include <iostream>
#include <cstring>
using namespace std;
bool map[505][505], used[505];
int girl[505];
int k, m ,n;
bool find(int num) {
for(int i = 1; i <= m; i++) {
if(map[num][i] == 1 && used[i] == 0) { //used的作用是寻找匹配点寻找非匹配边时,防止找到匹配边,就是怕自己找到自己
used[i] = 1;
if(girl[i] == 0 || find(girl[i])) {
girl[i] = num;
return true;
}
}
}
return false;
}
int main(void) {
while(cin >> k && k ) {
cin >> m >> n;
memset(used, false, sizeof(used));
memset(map, false, sizeof(map));
memset(girl, 0, sizeof(girl));
int term1, term2;
for(int i = 0; i < k; i++) {
cin >> term1 >> term2;
map[term2][term1] = true;
}
int sum = 0;
for(int i = 1; i <= n; i++) {
memset(used, false, sizeof(used));
if(find(i)) {
sum++;
}
}
cout << sum << endl;
}
return 0;
}