匈牙利算法 二分图

转载自一位大大大大犇:

https://www.cnblogs.com/shenben/p/5573788.html

匈牙利算法基本模板

#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 3;
int n = maxn, m = maxn;
int Map[maxn][maxn];//map[i][j]=1表示X部的i和Y部的j存在路径,是否可以匹配
int cx[maxn], cy[maxn];
bool vis[maxn];
//cx[i]表示X部i点匹配的Y部顶点的编号
//cy[i]表示Y部i点匹配的X部顶点的编号
 
bool dfs(int u)//dfs进入的都是X部的点
{
	for (int v = 0; v < n; v++)//枚举Y部的点,判断X部的u和Y部的v是否存在路径
	{
		//如果存在路径并且还没被标记加入增广路
		if (Map[u][v] && !vis[v])//vis数组只标记Y组
		{
			//标记加入增广路
			vis[v] = 1;
 
			//如果Y部的点v还未被匹配
			//或者已经被匹配了,但是可以从v点原来匹配的cy[v]找到一条增广路
			//说明这条路就可是一个正确的匹配
			//因为递归第一次进入dfs时,u是未匹配的
			//如果v还没有匹配对象,即和它相连的所有边都不在,已经选择的匹配边集合M(M\in E)中,这时就找到了u-v增广路径
			//如果v已经有匹配对象了,那么u-v是一条未选择的边,而v-cy[v] \in M 则是一条已经选择的边, dfs(cy[v])从cy[v]开始搜索增广路径
				//如果新的v'没有匹配对象,那么u-v-cy[v]-v'就是一条增广路径,如果v'已经有匹配对象了,那么根据匹配是唯一的,cy[v]-v'一定不在已经选择的边中(和cy[v]-v冲突),u-v-cy[v]-v'-cy[v']符合增广路径对边顺序的要求,继续利用dfs(cy[v'])搜索u-v-cy[v]-v'-cy[v']-下面的点
				//当搜索到增广链时,如u-v-cy[v]-v',那么经过递归的匹配调整和return 1,进行匹配增广操作,假设dfs0 是main调用的dfs算法,dfs1是dfs0调用的dfs算法
				//在dfs1中进行cy[v]-v'的匹配,因为dfs1返回1,因此在dfs0中进行u-v的匹配,匹配增广操作的结果是{cy[v]-v}->{u-v,cy[v]-v'}
				//如果在一个dfs(k)自调用的dfs(k+1)中,遍历所有的v(k+1),要么已经有匹配点了,要么和输入u(k+1)没有连接可能,这时搜索终止,说明不存在经过u(k+1)的增广链,返回0
				//而在main调用的dfs(0)中,调用的dfs(1)返回的都是0,而且v都是已经有匹配了,那么不存在从该点出发的增广链,那么就该点就不在最大匹配当中
				//为什么找不到增广链就不在最大匹配当中呢?感觉可以用反证法证明,博客中下面内容可能有更新这方面的思考
			if (cy[v] == -1 || dfs(cy[v]))
			{
				cx[u] = v;//可以匹配,进行匹配
				cy[v] = u;
				return 1;
			}
		}
	}
	return 0;//不能匹配
}
int maxmatch()//匈牙利算法主函数
{
	int ans = 0;
	//匹配清空,全部置为-1
	memset(cx, -1, sizeof(cx));
	memset(cy, -1, sizeof(cy));
	for (int i = 0; i < n; i++)
	{
		if (cx[i] == -1)//如果X部的i还未匹配
		{
			memset(vis, 0, sizeof(vis));//每次找增广路的时候清空vis
			ans += dfs(i);
		}
	}
	return ans;
}
 
int main_test()
{
	//输入匹配的两个点集合的数量
	cin >> n >> m;
	//输入两个点集合成员间的匹配可能
	int x, y;
	for (int i = 0; i < m; i++)
	{
		cin >> x >> y;
		Map[x][y] = 1;
	}
	//执行匈牙利算法,输出最大匹配
	cout << maxmatch() << endl;
}

N - Jimmy’s Assignment :https://vjudge.net/contest/310915#problem/N
用vector会超时 邻接矩阵会卡空间 优化采用邻接表来储存二分图 尽量采用while循环
还有就是上周比赛一道水题用的FOR循环一直WA 真的不知道是为什么 后来用了WHILE循环才AC 也就是那一次过后我专门去搜了一下题 结果发现while循环居然比for循环快 我真的是太菜菜菜菜了
vector:

#include<set>
#include<map>
#include<string.h>
#include<string>
#include<vector>
#include<iostream>
#include<queue>
#include<algorithm>
#include<math.h>
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f

using namespace std;
const int maxm=1212;
const int maxn=8010;
int cy[maxn];
bool vis[maxn];
int n;


vector<int>q[maxn];

bool dfs(int x)
{
    int i,v;
    for(i=0;i<q[x].size();i++)
    {
        v=q[x][i];//可以与妹子匹配的男士
        if(!vis[v])//vis数组只对妹子进行标记
        {
            vis[v]=1;
            if(cy[v]==-1||dfs(cy[v]))//妹子还没有和他匹配的男生
            {             或者妹子已经名花有主就需要我们回溯到和这个妹子匹配的男生寻找一个新的男朋友
                cy[v]=x;
                return true;
            }
        }
    }
    return false;
}
int main()
{
    int T,x,y,i;
    scanf("%d",&T);
    while(T--)
    {
        cin>>n;
        int m=3*n/2;
        for(i=0;i<=n;i++)
            q[i].clear();
        while(m--)
        {
            scanf("%d%d",&x,&y);
            q[x].push_back(y);
            q[y].push_back(x);
        }
        int ans=0;
        mem(cy,-1);
        for(i=1;i<=n;i++)
        {
            //如果X部的男生还没有妹子和他进行约会
            mem(vis,0);
            ans+=dfs(i);
        }
        printf("%d\n",ans/2);
    }
    return 0;
}

邻接表:

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std;
const int MAXN = 5010;
const int MAXM = 50010;

struct Edge
{
    int to, next;
} edge[MAXM];
int head[MAXN], tot;
int linker[MAXN];
bool used[MAXN];
int n, m;

void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
}

void addEdge(int u, int v)
{
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;
}

bool dfs(int u)
{
    for (int i = head[u]; i != -1; i = edge[i].next)
    {
        int v = edge[i].to;
        if (!used[v])
        {
            used[v] = true;
            if (linker[v] == -1 || dfs(linker[v]))
            {
                linker[v] = u;
                return true;
            }
        }
    }
    return false;
}

int solve()
{
    int ans = 0;
    memset(linker, -1, sizeof(linker));
    for (int i = 0; i < n; i++)
    {
        memset(used, false, sizeof(used));
        if (dfs(i))
            ans++;
    }
    return ans;
}

int main()
{
    int t;
    scanf("%d",&t);
    while (t--)
    {
        scanf("%d", &n);
        m = n*3/2;
        int u,v;
        init();
        while (m--)
        {
            scanf("%d%d", &u, &v);
            u--;
            v--;
            addEdge(u,v);
            addEdge(v,u);
        }
        printf("%d\n", solve()/2);
    }
    return 0;
}
基于STM32F407,使用DFS算法实现最短迷宫路径检索,分为三种模式:1.DEBUG模式,2. 训练模式,3. 主程序模式 ,DEBUG模式主要分析bug,测量必要数据,训练模式用于DFS算法训练最短路径,并将最短路径以链表形式存储Flash, 主程序模式从Flash中….zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值