二分图的染色与匹配
2017-09-30 11:54
316 查看
二分图:图中点集可分成两部分,使处于同一部分的点间没有连边
染色法,是一种简单地判断是否为二分图的方法.
对图中的每个点进行染色,使相临的点颜色不同,如果可以完成则为二分图,否则不为.
BFS实现:
DFS实现:
http://acm.hdu.edu.cn/showproblem.php?pid=5285 wyh2000 and pupil
poor wyh…
二分图匹配算法:匈牙利算法
https://www.luogu.org/problem/show?pid=3386 二分图匹配模板
推荐博客:http://www.cnblogs.com/shenben/p/5573788.html 对匈牙利算法进行详尽的理解
推荐题目:http://codevs.cn/problem/1222/ 信与信封问题
先进行一次匹配,再对匹配的边依次删除,如果不能完美匹配,说明这条边是不可或缺的,则将这条边输出
染色法,是一种简单地判断是否为二分图的方法.
对图中的每个点进行染色,使相临的点颜色不同,如果可以完成则为二分图,否则不为.
BFS实现:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<queue> using namespace std; int n,m,ru,rv,tot; int first[100010],nxt[100010],color[100010]; bool flag; struct edge { int u,v; }l[100010]; queue<int>q; void build(int f,int t) { l[++tot]=(edge){f,t}; nxt[tot]=first[f]; first[f]=tot; } int bfs(int s) { q.push(s); color[s]=1; while(!q.empty()) { int k=q.front(); q.pop(); for(int i=first[k];i!=-1;i=nxt[i]) { int x=l[i].v; if(color[x]==-1) { q.push(x); color[x]=color[k]^1;//color[x]=!color[k]; } if(color[x]==color[k]) return 0; } } return 1; } int main() { memset(first,-1,sizeof(first)); memset(color,-1,sizeof(color)); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d%d",&ru,&rv); build(ru,rv); build(rv,ru); } for(int i=1;i<=n;i++)//遍历每一个点 { if(color[i]==-1&&first[i]!=-1)//若起始点没有染过色(此点及此点可到达的点未被染色)并且起始点有出边 { if(!bfs(i)) flag=1; } } if(flag==1) printf("NO"); else printf("YES"); return 0; }
DFS实现:
http://acm.hdu.edu.cn/showproblem.php?pid=5285 wyh2000 and pupil
poor wyh…
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; int n,m,ru,rv,tot,zero,one,t,ans1,ans2; int first[200010],nxt[200010],color[200010]; bool flag; struct edge { int u,v; }l[200010]; void build(int f,int t) { l[++tot]=(edge){f,t}; nxt[tot]=first[f]; first[f]=tot; } void dfs(int s) { for(int i=first[s];i!=-1;i=nxt[i]) { int x=l[i].v; if(color[x]==color[s]) flag=1; if(color[x]!=-1) continue; if(color[x]==-1) { color[x]=color[s]^1; if(color[x]==1) one++; else zero++; } dfs(x); } } int main() { scanf("%d",&t); for(int i=1;i<=t;i++) { tot=0; memset(first,-1,sizeof(first)); memset(color,-1,sizeof(color)); scanf("%d%d",&n,&m); if(n<=1) { printf("Poor wyh\n"); continue; } if(m==0) { printf("%d 1\n",n-1); continue; } for(int i=1;i<=m;i++) { scanf("%d%d",&ru,&rv); build(ru,rv); build(rv,ru); } ans1=ans2=flag=0; for(int i=1;i<=n;i++) { if(color[i]==-1&&first[i]!=-1) { one=1; zero=0; color[i]=1; dfs(i); ans1+=max(one,zero); ans2+=min(one,zero); } if(color[i]==-1&&first[i]==-1) ans1++; } if(flag==1) printf("Poor wyh\n"); else printf("%d %d\n",ans1,ans2); } return 0; }
二分图匹配算法:匈牙利算法
https://www.luogu.org/problem/show?pid=3386 二分图匹配模板
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; int n,m,e,ru,rv,ans,tot; int x[100010],y[100010],first[500010],nxt[500010]; bool vis[100010]; struct edge { int u,v; }l[500010]; void build(int f,int t) { l[++tot]=(edge){f,t}; nxt[tot]=first[f]; first[f]=tot; } int path(int k) { for(int i=first[k];i;i=nxt[i]) { int t=l[i].v; if(!vis[t]) { vis[t]=1; if(!y[t]||path(y[t]))//若t没有匹配或与t匹配的点y[t]可以寻找一条增广路与其他的点进行匹配 { x[k]=t;//匹配 y[t]=k; return 1; } } } return 0; } int main() { scanf("%d%d%d",&n,&m,&e); for(int i=1;i<=e;i++) { scanf("%d%d",&ru,&rv); if(ru>n||rv>m)//洛谷数据有误... continue; build(ru,rv); } for(int i=1;i<=n;i++) { if(!x[i]) { memset(vis,0,sizeof(vis)); ans+=path(i);//统计匹配数 } } printf("%d",ans); return 0; } 二分图的最小顶点覆盖数=二分图的最大匹配数 二分图的最小路径覆盖数=点的数量-二分图的最大匹配数 二分图的最小边覆盖数=点的数量-二分图的最大匹配数 二分图的最大独立集大小=点的数量-二分图的最大匹配数
推荐博客:http://www.cnblogs.com/shenben/p/5573788.html 对匈牙利算法进行详尽的理解
推荐题目:http://codevs.cn/problem/1222/ 信与信封问题
先进行一次匹配,再对匹配的边依次删除,如果不能完美匹配,说明这条边是不可或缺的,则将这条边输出
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; int n,x,y,ans; int lkx[100010],lky[100010],mp[2500][2500]; bool flag; bool vis[100010]; int path(int k) { for(int i=1;i<=n;i++) { if(!mp[k][i]&&!vis[i]) { vis[i]=1; if(!lky[i]||path(lky[i])) { lkx[k]=i; lky[i]=k; return 1; } } } return 0; } int main() { scanf("%d",&n); while(1) { scanf("%d%d",&x,&y); if(x==0&&y==0) break; mp[x][y]=1; } for(int i=1;i<=n;i++) { memset(vis,0,sizeof(vis)); if(path(i)) ans++; } if(ans!=n) printf("none"); else { for(int i=1;i<=n;i++) { memset(vis,0,sizeof(vis)); int tmp=lkx[i]; mp[i][tmp]=1; lkx[i]=0; lky[tmp]=0; if(!path(i)) { printf("%d %d\n",i,tmp); lkx[i]=tmp; lky[tmp]=i; flag=1; } mp[i][tmp]=0; } if(!flag) printf("none"); } return 0; }
相关文章推荐
- poj 2446 二分图最大匹配(奇偶图)网上貌似叫(黑白染色图)
- Codevs 3052 多米诺 (二分图染色+二分图最大匹配)
- AcDream 1729 Crime【二分匹配+二分图染色】水题= =
- HDU 2444 The Accomodation of Students【二分图染色+匹配*好题】
- [kuangbin带你飞]专题十 匹配问题 (二分图最大匹配)(二分图染色)(模板)
- UVA Live 7958 (Codeforces Gym 101201G) Maximum Islands 二分图染色+匹配
- HDU 2444 黑白染色判二分图+二分最大匹配
- 1507 Uncle Tom's Inherited Land* 二分图-----黑白染色+奇偶匹配(1X2的矩形覆盖)
- hdu 2444 交叉染色判断二分图+二分最大匹配
- [codevs1022]覆盖(染色+二分图最大匹配)
- HUD 2444 The Accomodation of Students (二分图染色+最大匹配)
- hdu 2444 交叉染色判断二分图+二分最大匹配
- Gym 101201F Illumination 2-sat+ G - Maximum Islands Gym - 101201G二分图染色+匹配
- hdu 2444(染色法判断二分图+最大匹配)
- hdoj 2444 The Accomodation of Students 【黑白染色判二分图 + 最大匹配】
- HDU2444 二分图判断(BFS 的染色法) + 求最大匹配边数(DFS 的匈牙利算法)
- [HDOJ2444]The Accomodation of Students(二分图染色判定,最大匹配,匈牙利算法)
- 2008年第33届ACM/ICPC亚洲区预赛(哈尔滨)网络预选赛 1007__The Accomodation of Students 二分图最大匹配+染色
- hdu 1507 Uncle Tom's Inherited Land*(二分图最大匹配,黑白染色)
- HDU2444 The Accomodation of Students(染色法判断二分图+最大匹配)