二分图:简单的说就是把图中的点分成二组,并且使得所有的边都跨越组的边界。
匹配:任意二条边都没有公共都顶点
最大匹配:一个图的匹配边数最多
完美匹配:一个图中的某个匹配中,所有的顶点都是匹配点
交替路:从一个未匹配的点出发,走交替路 依此经过匹配边 非匹配边 匹配边 ......形成的路径叫交替路
增广路:从一个未匹配点出发走交替路,经过一个未匹配的点
最大独立数:选取最多的点 使任意所选二点均不相连
最小点覆盖数:选取最少的点 是任意一条边至少有一个端点被选择
最小路径覆盖数:对于一个DAG(有向无环图)选取最少点边 使得每个顶点属于且仅属于一条路径
定理1:最大匹配数=最小点覆盖数
定理2:最大匹配数=最大独立数
定理3:最小路径覆盖数=顶点数-最大匹配数
下面是二分图的判断:
const int MAX=10010;
vector<int>G[MAX];
int edge[MAX][MAX];
int col[MAX];
int n;
int dfs(int u,int c){
col[u]=c;
for(int i=0;i<n;i++){
if(edge[u][i]==1){
if(col[i]==c) return 0;
if(col[i]==0&&!dfs(i,-c)) return 0;
}
}
return 1;
}
int bfs(int u){
queue<int>q;
q.push(u);
col[u]=1;
while (!q.empty()) {
int v=q.front();
q.pop();
for(int i=0;i<G[v].size();i++){
int x=G[v][i];
if(col[x]==0){
col[x]=-col[v];
q.push(x);
}
else {
if(col[x]==col[v])
return 0;
}
}
}
return 1;
}
void solve(){
for(int i=1;i<=n;i++){
if(col[i]==0&&!bfs(i))
{
cout<<"NO"<<endl;
return;
}
}
cout<<"YES"<<endl;
}
最大匹配的匈牙利算法:
const int MAX=100010;
vector<int>G[MAX];
int n,m;
int vis[MAX],pei[MAX];
int dfs(int u){
for(int i=0;i<G[u].size();i++){
int v=G[u][i];
if(!vis[v]){
vis[v]=1;
if(!pei[v]||dfs(pei[v])){
pei[v]=u;
return 1;
}
}
}
return 0;
}
void solve(){
int ans=0;
for(int i=1;i<=n;i++){
mms(vis,0);
if(dfs(i))
ans++;
}
cout<<ans<<endl;
}
最大权的匹配KM:
求二分图中最大匹配的边权和最大
const int MAX=1e3+10;
int wx[MAX],wy[MAX];
int matchx[MAX];
int matchy[MAX];
int visx[MAX];
int visy[MAX];
int cntx=MAX;
int cnty=MAX;
int mp[MAX][MAX];
int d;
int dfs(int u){
visx[u]=1;
for(int v=0;v<cnty;v++){
if(!visy[v]&&mp[u][v]!=INF){
int t=wx[u]+wy[v]-mp[u][v];
if(t==0){
visy[v]=1;
if(matchy[v]==-1||dfs(matchy[v])){
matchx[u]=v;
matchy[v]=u;
return 1;
}
}
else if(t>0){
d=min(d,t);
}
}
}
return 0;
}
int km(){
mms(matchx,-1);
mms(matchy,-1);
mms(wx,0);
mms(wy,0);
for(int i=0;i<cntx;i++){
for(int j=0;j<cnty;j++){
if(mp[i][j]==INF)
continue;
wx[i]=max(wx[i],mp[i][j]);
}
}
for(int i=0;i<cntx;i++){
while (1) {
d=INF;
mms(visx,0);
mms(visy,0);
if(dfs(i)) break;
for(int j=0;j<cntx;j++)
if(visx[j]) wx[j]-=d;
for(int j=0;j<cnty;j++)
if(visy[j]) wy[j]+=d;
}
}
int ans=0;
for(int i=0;i<cntx;i++){
if(matchx[i]!=-1)
ans+=mp[i][matchx[i]];
}
return ans;
}
int n,k;
int main(){
cin>>n;
for(int i=0;i<n;i++){
for(int j=0;j<n;j++)
cin>>mp[i][j];
}
cout<<km()<<endl;
}