最小生成树与二分图(染色算法与匈牙利算法)模板与详解

最小生成树与二分图模板记忆

最小生成树与二分图知识架构
最小生成树{
	Prim algorithm{
		1.朴素版Prim O(O^2) 稠密图{
			将所有点初始化为正无穷
			迭代n次
			找到集合外最近的点
			判断是不是这个点是不是连通的
			如果不是第一条边就进行累加
			用这个点更新集合外的点到集合的距离(不更新累加距离,只更新最短距离)
			标记这个集合并加入集合
		}

		2.堆优化Prim O(mlogn) 稀疏图{//一般不用,用克鲁斯卡尔代替
			这里就先不写了...
		}
	}

	Kruskal algorithm{ O(mlogm) 稀疏图
		1.将所有边按权重从小到大排序 O(mlogm)
		2.初始化并查集
		3.从小到大枚举每条边(a-b权重c),若a,b不连通,将a,b加入集合中
	}
}

二分图

二分图{//一个图是二分图当且仅当图中不含奇数环
	1.染色法{ O(n+m)
		1.建邻接表
		2.for(1~n)
			if(i未染色)
				dfs(i)
		需要标记每个点是否被染色
	}
	2.匈牙利算法{ O(nm),实际运行时间远小于O(nm)
		最快时间内得出二分图成功匹配的最大的数量(成功匹配:没有两条边共用一个点)
		
	}
	最大流算法
}

最小生成树

Prim algorithm
#define MAXN 510

#define INF 0x3f3f3f3f
int n,m;
int g[MAXN][MAXN],dis[MAXN];
bool st[MAXN];

int prim(){
    memset(dis,0x3f,sizeof(dis));
    
    int res=0;
    //n次迭代
    for(int i=1;i<=n;i++){
        int t=-1;
        
        for(int j=1;j<=n;j++)
            if(!st[j]&&(t==-1||dis[t]>dis[j]))
                t=j;
               
        if(i!=1&&dis[t]==INF) return INF;
        if(i!=1) res+=dis[t];
        
        for(int j=1;j<=n;j++) 
            dis[j]=min(dis[j],g[t][j]);
            
        st[t]=true;
    }
    return res;
}

### 二分图算法
二分图{//一个图是二分图当且仅当图中不含奇数环
	1.染色法{ O(n+m)
		1.建邻接表
		2.for(1~n)
			if(i未染色)
				dfs(i)
		需要标记每个点是否被染色
	}
	关键的bool dfs:
		1.标记颜色
		2.遍历此点所有连接的点,如果没有被染色,则染色并dfs,若返回false 则返回false(这里的迭代十分关键,看代码)
		3.否则如果染过颜色,则判断颜色是都矛盾
		4.都没问题返回true
代码:
	bool dfs(int x,int k){
    color[x]=k;
    for(int i=h[x];i!=-1;i=ne[i]){
        int j=e[i];
        if(!color[j]){
            if(!dfs(j,3-k)) return false;
        }
        else if(color[j]==k) return false;
    }
    return true;
}
//之后的main函数内:
for(int i=1;i<=n;i++){
    if(!color[i]){
        if(!dfs(i,1)){
            flag=false;
            break;
        }
    }
}
if(!flag) puts("No");
else puts("Yes");

### 匈牙利算法
遍历二分图要找的点每一个对应点
如果此点不在配对成功的集合中{
	将此点加入配对成功的集合
	如果此映射点没有被配对或者将其配对的点有其他可配对的点,则返回配对成功(对应函数外侧更新答案)
}
代码:
bool find(int x){
    for(int i=h[x];i!=-1;i=ne[i]){
        int j=e[i];
        if(!st[j]){
            st[j]=true;
            if(match[j]==0||find(match[j])){
                match[j]=x;
                return true;
            }
        }
    }
    return false;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值