相关知识点
- 最小点覆盖 = 最大匹配。
- 最大独立集 = 所有顶点数 - 最小顶点覆盖
- 最大团 = 补图的最大独立集
- 最小路径覆盖 = |G|-最大匹配
最大匹配算法
匈牙利算法
bool dfs(int u)
{
for(int i=0;i<n;i++)
if(g[u][i]&&!used[i])
{
used[i]=true;
if(linker[i]==-1||dfs(linker[i]))
{
linker[i]=u;
return true;
}
}
return false;
}
int hungary()
{
int res=0;
memset(linker,-1,sizeof(linker));
for(int i=0;i<n;i++)
{
memset(used,0,sizeof(used));
if(dfs(i)) res++;
}
return res;
}
KM算法
O(n^4)
bool match(int u){
S[u] = true;
for(int i=1;i<=n;i++){
if(w[u][i] == lx[u] + ly[i] && !T[i]){
T[i] = true;
if(!linker[i] || match(linker[i])){
linker[i]= u;
return true;
}
}
}
return false;
}
void updata(){
int a = inf;
for(int i=1;i<=n;i++) if(S[i])
for(int j=1;j<=n;j++) if(!T[j])
a = min(a,lx[i] + ly[j] - w[i][j]);
for(int i=1;i<=n;i++){
if(S[i]) lx[i] -= a;
if(T[i]) ly[i] += a;
}
}
int KM(){
for(int i=1;i<=n;i++){
linker[i] = lx[i] = ly[i] = 0;
for(int j=1;j<=n;j++)
lx[i] = max(lx[i],w[i][j]);
}
for(int i=1;i<=n;i++){
while(1){
for(int j=1;j<=n;j++) S[j] = T[j] = 0;
if(match(i)) break;
else updata();
}
}
int res = 0;
for(int i=1;i<=n;i++){
if(linker[i])
res += w[linker[i]][i];
}
return res;
}
O(n^3)
#include <bits/stdc++.h>
using namespace std;
int const N = 300 + 10;
int const inf = 0x7f7f7f7f;
int n,w[N][N],linker[N],S[N],T[N],lx[N],ly[N],slack[N];
bool match(int u){
S[u] = true;
for(int i=1;i<=n;i++){
if(T[i]) continue;
int tmp = lx[u] + ly[i] - w[u][i];
if(tmp == 0){
T[i] = true;
if(!linker[i] || match(linker[i])){
linker[i]= u;
return true;
}
}else slack[i] = min(slack[i],tmp);
}
return false;
}
void updata(){
int a = inf;
for(int i=1;i<=n;i++) if(!T[i])
a = min(a,slack[i]);
for(int i=1;i<=n;i++){
if(S[i]) lx[i] -= a;
if(T[i]) ly[i] += a;
//else slack[i] -= a; //加不加都可以过,时间慢一点
}
}
int KM(){
for(int i=1;i<=n;i++){
linker[i] = lx[i] = ly[i] = 0;
for(int j=1;j<=n;j++)
lx[i] = max(lx[i],w[i][j]);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++) slack[j] = inf;
while(1){
for(int j=1;j<=n;j++) S[j] = T[j] = 0;
if(match(i)) break;
else updata();
}
}
int res = 0;
for(int i=1;i<=n;i++){
if(linker[i])
res += w[linker[i]][i];
}
return res;
}
int main(){
while(~scanf("%d",&n)){
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&w[i][j]);
printf("%d\n",KM());
}
return 0;
}