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;
}
posted @   _XOFqwq  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示