1、什麼是二分圖
可以把頂點分成X,Y兩個集合,且每個集合裏沒有相鄰的邊(相連)。
2、二分圖有哪些問題
2.1 二分圖的判定
關於二分圖的判定,一般使用染色判斷法,即把邊兩端的定點顏色染成不同顏色觀察是否衝突。
模板:
bool judge(int u){
for (int i=head[u];~i;i=e[i].nxt){
int v=e[i].to;
if (!col[v]){
col[v]=!col[u];
if (!judge(v)) return 0;
}
else if (col[v]==col[u])
return 0;
}
return 1;
}
if (judge(1)) return true;
2.2 二分圖匹配問題
2.2.1 二分圖最大匹配
採用匈牙利算法,注意頂點數/2,O(VE),有bfs和dfs兩個版本,對於稀疏圖bfs快,稠密圖差不多,dfs優點在於好寫。
bool dfs(int u){
for (int i=head[u];~i;i=e[i].nxt){
int v=e[i].to;
if (!vis[v]){
vis[v]=1;
if (link[v]==-1 || dfs(link[v])){
link[v]=u;
return 1;
}
}
}
return 0;
}
int match(){
int ans=0;
memset(link,-1,sizeof(link));
for (int i=1;i<=n;i++){
memset(vis,0,sizeof(vis));
if (dfs(i)) ans++;
}
return ans;
}
2.2.2 二分圖完全匹配
完全匹配是一個驗證問題,只要把2.2.1的ans和頂點數/2相比即可。
2.2.3 二分圖帶權匹配
KM算法,O(n^3)。
// 最小費用最大流 KM算法 帶權二分圖匹配
// KM算法是求最大權值匹配,求最小權值匹配,只需要將所有邊權取負。
// 邊權之積最大 取對數
// S->{X} 權值爲0,容量爲1。
// {Y}->T 權值爲0,容量爲1。
// 原有的邊 權值不變,容量爲1。
// 鄰接矩陣 不適合稀疏圖
// 如果可以非完全匹配,引入頂點A,{X}->A 容量爲1,權值爲0.
// A->T 權值爲0,容量不小於|X|
const int ME=1010;
const int MV=100;
struct edge{
int to,nxt,flow;
db cost;
}e[ME];
int head[MV],cnt;
queue<int> q;
int cur[MV],pre[MV];
bool used[MV],sign[MV];
int flow,n,m;
db cost,dis[MV];
double p[16][1024];
bool spfa(int s,int t){
memset(used,0,sizeof(used));
memset(sign,0,sizeof(sign));
memset(dis,0,sizeof(dis));
used[s]=sign[s]=1;
while (!q.empty()) q.pop();
q.push(s);
while (!q.empty()){
int u=q.front();
q.pop();
used[u]=0;
for (int i=head[u];~i;i=e[i].nxt){
if (e[i].flow<1) continue;
int v=e[i].to;
db c=e[i].cost;
if (!sign[v] || dis[v]>dis[u]+c){
dis[v]=dis[u]+c;
sign[v]=1;
pre[v]=u;
cur[v]=i;
if (used[v]) continue;
used[v]=1;
q.push(v);
}
}
}
return sign[t];
}
void init(){
cnt=0;
memset(head,-1,sizeof(head));
}
void add(int u,int v,int flow,db cost){
e[cnt].to=v, e[cnt].flow=flow, e[cnt].cost=cost;
e[cnt].nxt=head[u], head[u]=cnt++;
e[cnt].to=u, e[cnt].flow=0, e[cnt].cost=-cost;
e[cnt].nxt=head[v], head[v]=cnt++;
}
void solve(int s,int t){
flow=cost=0;
while (spfa(s,t)){
int tmp=t;
int now=inf;
while (tmp!=s){
now=min(now,e[cur[tmp]].flow);
tmp=pre[tmp];
}
flow+=now;
tmp=t;
while (tmp!=s){
int id=cur[tmp];
cost+=now*e[id].cost;
e[id].flow-=now;
e[id^1].flow+=now;
tmp=pre[tmp];
}
}
}
db getcost(){
return cost;
}
3、可以轉化成二分圖的問題
3.1 最小路徑覆蓋
頂點數-最大匹配。
3.2 最小頂點覆蓋
最大匹配
3.3 最小邊覆蓋
最大匹配
3.4 最大獨立集
頂點數-最大匹配。