poj 3041 二分图基础知识+匈牙利算法模版

二分图的定义:如果图的顶点可以分为2个互不相交的子集(A,B),则称这个图为二分图。

完全二分图:是指二分图两个集合中每个顶点与另外一个集合的所有顶点都有权值相连。

匹配:匹配是把两两存在公共边的的结点且未被匹配的结点相连。

增广路径:如果一条路径的首尾是非匹配点,路径中除此之外,其他的点均为匹配点,那么这条路径是一条增广路径。2个点也是一个增广路径。

每个增广路径都能变为比原来多一个匹配。

输入n,m  n为左边子集数,b有右边子集数,然后接下来m行表示m连接的点有哪些

样例输入:

4 6
1 1
1 1
5 1 3 4 5 6

4 4 5 6

样例输出:

3

代码:

#include <iostream>
#include <string.h>
using namespace std;

bool map[105][105],used[105];
int lin[105],n,m;

bool search(int a){
	for(int i=1;i<=m;i++){
		if(used[i]==0&&map[a][i]){
			used[i]=1;
			cout << a << "---->" << i << endl;
			if(lin[i]==-1||search(pre[i])){
				lin[i]=a;
				cout << a  << "连上" << i << endl;
				return 1;
			}
		}
	}
	return 0;
}

int main(){
	freopen("in.txt","r",stdin);
	int t1,t2,i,j,count=0;
	cin >> n >> m;
	memset(map,0,sizeof(map));
	memset(lin,-1,sizeof(lin));
	for(i=1;i<=n;i++){
		cin >> t1;
		for(j=1;j<=t1;j++){
			cin >> t2;
			map[i][t2]=1;
		}
	}
	for(i=1;i<=n;i++){
		memset(used,0,sizeof(used));
		if(search(i))count++;
	}
	cout << "最大匹配图有" << count << endl;
}


最大二分图匹配复习,用vector来

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
vector<int>out[550];
int indegree[550];
int pre[550];
int walked[550];

int bfs(int x){
    if(walked[x]==0){
    walked[x]=1;
    for(int i=0;i<out[x].size();i++){
        if(pre[out[x][i]]==0||bfs(pre[out[x][i]])){
            pre[out[x][i]]=x;
            //cout << x << "pre---" << out[x][i] << endl;
            return 1;
        }
    }
    }
    return 0;
}
int main(){
    freopen("in.txt","r",stdin);
    int i,j,k,l,f1,f2,f3,t1,t2,t3;
    int n,m;
    scanf("%d%d",&n,&m);
    memset(indegree,0,sizeof(indegree));
    memset(out,0,sizeof(out));
    memset(pre,0,sizeof(pre));
    for(i=1;i<=n;i++){
        cin >> f1;
        for(j=1;j<=f1;j++){
            cin >> f2;
            out[i].push_back(f2);
        }
    }
    for(i=1;i<=n;i++){
            memset(walked,0,sizeof(walked));
    bfs(i);
    cout << i << endl;
    }
    for(i=1;i<=m;i++){
        cout << "i=" <<i <<"      "<<pre[i] << endl;
    }

    return 0;
}

poj 3041

给一个网格,然后给出小型星的坐标,每次激光可以选择一个x或一个y整条线上的小行星全部消除,问最少需要几次激光。

由行星只能被x或y方向的激光消灭,且一个行星对应一个x与y,那么可以把所有x和y作为结点,又行星作为边,建立二分图

最小顶点覆盖是指:图中任意一条边都有一个顶点s属于V。

也就是求出最少的顶点数,这些顶点连接的边包括了整个图的全部边。

对于二分图 最小顶点覆盖=最大匹配

最小顶点覆盖+最大独立集=V;

#include <iostream>
#include <stdio.h>
#include <queue>
#include <string.h>
#include <stdlib.h>
using namespace std;
vector<int>qq[550];
int pre[550];
int walked[550];
int dfs(int x){
	if(walked[x]==0){
	walked[x]=1;
	for(int i=0;i<qq[x].size();i++){
		int u=qq[x][i];
		if(pre[u]==-1||dfs(pre[u])){
			pre[u]=x;
			return 1;
		}
	}
}
	return 0;
}
int main(){
    //freopen("in.txt","r",stdin);
    int t1,t2,t3,f1,f2,f3,i,j,k,l,n,m;
    int k1,k2;
    int g1,g2;
    cin >> n>> m;
    memset(pre,-1,sizeof(pre));
    for(i=1;i<=m;i++){
    	cin >> t1>> t2;
    	qq[t1].push_back(t2);
    	//qq[t2].push_back(t1);
	}
	for(i=1;i<=n;i++){
		memset(walked,0,sizeof(walked));
	dfs(i);
	}
	t1=0;
	for(i=1;i<=n;i++){
		if(pre[i]!=-1)t1++;
	}
	cout << t1<< endl;
	return 0;	
}

dfs向下搜索发现pre被使用的时候,如果接着往下搜索,应该搜索pre[x]而不是x





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值