今天学习了匈牙利算法,顺便学习了一般图匹配的乱搞做法(被打死
模板题传送门:
http://uoj.ac/problem/78
http://uoj.ac/problem/79
二分图匹配的匈牙利算法
简要做法
匈牙利算法的主要思想是找增广路,和最大流算法类似。
每次对于一个点,找出一条交替路径,即匹配边、非匹配边交错,且开头结尾都是非匹配边的路径,并将这条路径上面的边取反(取->不取,不取->取),如果增广成功,则答案+1。
具体实现时,可以使用dfs来递归寻找增广路。
注意点
dfs过程中传入的顶点都是在图的一侧,同时vis数组要在每次增广之前清零,我因为这个WA了好几次...(菜不成声.jpg)
模板代码
//UOJ #78
#include
using namespace std;
const int MAXN=505;
void rd(int &x){
x=0; int ch=getchar();
while(ch<'0'||'9'
一般图匹配的乱搞随机做法
正解
对于一般图上的最大匹配问题,由于奇数长度环的存在,不能直接套用匈牙利算法。
一个经典的解法是带花树,代码也十分简短、优美,读者可以参考网上的一些资料。
然而博主太弱了,只会随机乱搞。
具体做法
外层循环T次,对于每个点,内层循环T次,寻找增广路,在每次dfs开始时,对该点的出边进行随机打乱。
这个算法效率较高,正确率...实测也不低(如果出题人没有丧心病狂卡数据的话)。
细节
你可能需要一些精心选择的参数。
顺便写了一下手写随机函数rand()。
模板代码
//UOJ #79
#include
using namespace std;
typedef unsigned long long ull;
const int MAXN=505, T=10, T2=10;
void rd(int &x){
x=0; int ch=getchar();
while(ch<'0'||'9'>16)&32767;
}
inline void shf(int *a, int n){
if(!n) return;
for(int t=0; tans) ans=tmp, memcpy(ma, m, sizeof(m));
} return ans;
}
int main(){
rd(N), rd(M);
for(int i=0, u, v; i