Living-Dream 系列笔记 第88期
二分图
定义:若可以将一张图分为两部分,且这两部分内部无连边,则称该图为二分图。
判定:无奇环。
判定证明:
-
必要性:若有奇环可以通过染色证明内部一定会有连边。
-
充分性:若无环显然一定可以划分,若有偶环则也可以通过染色证明合法。
实现:交替染色,只要碰到了要染色的点已染色且颜色与当前节点相同就不可以划分,否则可以。
UVA10004
模板。
code
#include<bits/stdc++.h> using namespace std; const int N=2e2+5; int n,m; int color[N]; vector<int> G[N]; void init(){ memset(color,0,sizeof color); for(int i=1;i<=n;i++) G[i].clear(); } bool check(int cur,int c){ color[cur]=c; for(int i:G[cur]){ if(color[i]==c) return 0; else if(!color[i]){ if(!check(i,3-c)) return 0; } } return 1; } int main(){ while(cin>>n&&n){ init(); cin>>m; for(int i=1,u,v;i<=m;i++){ cin>>u>>v; u++,v++; G[u].push_back(v); G[v].push_back(u); } bool f=1; for(int i=1;i<=n;i++){ if(color[i]) continue; if(!check(i,1)){ f=0; break; } } cout<<(f?"BICOLORABLE.\n":"NOT BICOLORABLE.\n"); } return 0; }
P1525
最大值最小想到二分。
两个监狱,考虑图论建模,自然想到二分图。
于是我们对于二分出的 \(x\),连边权 \(>x\) 的边表示排斥(即在不同监狱),这样同一监狱产生的冲突值都会 \(\le x\),判定其是否为二分图即可。
总结:挖掘题目中的提示,并考虑(特殊的)图论建模。
code
#include<bits/stdc++.h> #define int long long using namespace std; const int N=1e5+5; int n,m; int color[N]; struct Node{ int u,v,w; }e[N]; vector<int> G[N]; void init(){ memset(color,0,sizeof color); for(int i=1;i<=n;i++) G[i].clear(); } bool ok(int cur,int c){ color[cur]=c; for(int i:G[cur]){ if(color[i]==c) return 0; else if(!color[i]){ if(!ok(i,3-c)) return 0; } } return 1; } bool check(int x){ init(); for(int i=1;i<=m;i++){ if(e[i].w>x){ G[e[i].u].push_back(e[i].v); G[e[i].v].push_back(e[i].u); } } bool f=1; for(int i=1;i<=n;i++){ if(color[i]) continue; if(!ok(i,1)){ f=0; break; } } return f; } signed main(){ ios::sync_with_stdio(0); cin.tie(0); cin>>n>>m; int mx=-1e9; for(int i=1,u,v,w;i<=m;i++){ cin>>u>>v>>w; mx=max(mx,w),e[i]={u,v,w}; } int l=-1,r=mx+1; while(l+1<r){ int mid=(l+r)>>1; if(check(mid)) r=mid; else l=mid; } cout<<r; return 0; }
Hungary(饥饿)算法
解决二分图最大匹配问题。
称二分图中的一条边为匹配,则最大匹配是指这个图中最多的不共点匹配个数。
显然我们可以用 dfs 无脑找,但显然这太 man 了。
于是我们可以对于每个点去找一个匹配,然后遇到匹配不上的点,就尝试让它想要匹配的点已经匹配的那个点换一个人进行匹配。这就是饥饿算法的本质,即找增广路径。
P3386
code
// // P3386.cpp // // // Created by _XOFqwq on 2024/11/30. // #include <bits/stdc++.h> using namespace std; const int N=1e3+5; int n,m,e; int match[N]; bool vis[N]; vector<int> G[N]; bool dfs(int cur){ if (vis[cur]) { return 0; } vis[cur]=1; for (int i : G[cur]) { if (!match[i]||dfs(match[i])) { match[i]=cur; return 1; } } return 0; } int main(){ ios::sync_with_stdio(0); cin.tie(0); cin>>n>>m>>e; for (int i=1,u,v; i<=e; i++) { cin>>u>>v; G[u].push_back(v); } int ans=0; for (int i=1; i<=n; i++) { memset(vis,0,sizeof vis); //一次找到的不一定最优 if (dfs(i)) { ans++; } } cout<<ans; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】