二分图最佳匹配KM算法 /// 牛客暑期第五场E

题目大意:

给定n,有n间宿舍 每间4人

接下来n行 是第一年学校规定的宿舍安排

接下来n行 是第二年学生的宿舍安排意愿

求满足学生意愿的最少交换次数

input

2

1 2 3 4

5 6 7 8

4 6 7 8

1 2 3 5

output

2

题解

#include <bits/stdc++.h>
#define MAXN 205
#define INF 0x3f3f3f3f
using namespace std;
int n,mint;
int G1[MAXN][5],G2[MAXN][5];
int G[MAXN][MAXN],link[MAXN];
int x[MAXN],y[MAXN];
int visx[MAXN],visy[MAXN];
bool DFS(int s) {
    visx[s]=1;
    for(int i=1;i<=n;i++) {
        if(visy[i]) continue;
        int tmp=x[s]+y[i]-G[s][i];
        if(tmp==0) {
            visy[i]=1;
            if(link[i]==-1 || DFS(link[i])) {
                link[i]=s; return true;
            }
        }
        else if(tmp > 0) {
            mint=min(mint,tmp);
        }
    }
    return false;
}
void KM()
{
    for(int i=1;i<=n;i++) {
        link[i]=-1; y[i]=x[i]=0;
        for(int j=1;j<=n;j++)
            x[i]=max(x[i],G[i][j]);
    }
    for(int i=1;i<=n;i++) {
        while(1) {
            mint =INF;
            memset(visx,0,sizeof(visx));
            memset(visy,0,sizeof(visy));
            if(DFS(i)) break;
            for(int i=1;i<=n;i++) {
                if(visx[i]) x[i]-=mint;
                if(visy[i]) y[i]+=mint;
            }
        }
    }
    int out=0;
    for(int i=1;i<=n;i++) out+=G[link[i]][i];
    printf("%d\n",4*n-out);
}
int main()
{
    while(~scanf("%d",&n)) {
        for(int i=1;i<=n;i++)
            for(int j=1;j<=4;j++) scanf("%d",&G1[i][j]);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=4;j++) scanf("%d",&G2[i][j]);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++) {
                int cnt=0;
                for(int p=1;p<=4;p++)
                    for(int q=1;q<=4;q++)
                        if(G1[i][p]==G2[j][q]) cnt++;
                G[i][j]=cnt;
            }
        KM();
    }


    return 0;
}
View Code

KM算法讲解

https://blog.csdn.net/sixdaycoder/article/details/47720471

https://blog.csdn.net/c20180630/article/details/71080521

int n,mint;
int G[MAXN][MAXN],link[MAXN];
int x[MAXN],y[MAXN];
int visx[MAXN],visy[MAXN];
bool DFS(int s) {
    visx[s]=1;
    for(int i=1;i<=n;i++) {
        if(visy[i]) continue;
        int tmp=x[s]+y[i]-G[s][i];
        if(tmp==0) {
            visy[i]=1;
            if(link[i]==-1 || DFS(link[i])) {
                link[i]=s; return true;
            }
        }
        else if(tmp > 0) {
            mint=min(mint,tmp);
        }
    }
    return false;
}
void KM()
{
    for(int i=1;i<=n;i++) link[i]=-1; 
    for(int i=1;i<=n;i++) {
        while(1) {
            memset(visx,0,sizeof(visx));
            memset(visy,0,sizeof(visy));
            if(DFS(i)) break;
            for(int i=1;i<=n;i++) {
                if(visx[i]) x[i]-=mint;
                if(visy[i]) y[i]+=mint;
            }
        }
    }
}
模板

猜你喜欢

转载自www.cnblogs.com/zquzjx/p/9420901.html