模板 KM算法

\(KM\)算法计算带权二分图最优匹配
模板一:\(dfs\)算法,时间复杂度\(O(n^4)\)

const int maxn=310;
const LL inf=0x3f3f3f3f3f3f3f3f;

//match[i]=j表示右边的第i个点匹配左边的第j个点,也可能这两个点之间其实没有连边,也就是权值为零
int n,match[maxn];
LL g[maxn][maxn],ex1[maxn],ex2[maxn],slack[maxn];    
bool vis1[maxn],vis2[maxn];

bool dfs(int x){
    vis1[x]=true;
    for(int y=1;y<=n;y++) {
        if(vis2[y]) continue; 
        LL gap=ex1[x]+ex2[y]-g[x][y];
        if(gap==0){  
            vis2[y]=true;
            if(match[y]==-1 || dfs(match[y])){   
                match[y]=x;
                return true;
            }
        } 
        else{
            slack[y]=min(slack[y],gap);  
        }
    }
    return false;
}

LL KM(){
    memset(match,-1,sizeof(match));    
    memset(ex2,0,sizeof(ex2));  
    for(int i=1;i<=n;i++){
        ex1[i]=g[i][1];
        for(int j=1;j<=n;j++){
            ex1[i]=max(ex1[i],g[i][j]);
        }
    }
    for(int i=1;i<=n;i++){
        memset(slack,0x3f,sizeof(slack));    
        while(1){
            memset(vis1,false,sizeof(vis1));
            memset(vis2,false,sizeof(vis2));
            if(dfs(i)) break;
            LL d=inf;
            for(int j=1;j<=n;j++)
                if(!vis2[j]) d=min(d,slack[j]);
            for(int j=1;j<=n;j++){
                if(vis1[j]) ex1[j]-=d;
                if(vis2[j]) ex2[j]+=d;
                else slack[j]-=d;
            }
        }
    }
    LL res=0;
    for(int i=1;i<=n;i++)
        res+=g[match[i]][i];
    return res;
}

模板题:hdu2255 奔小康赚大钱

模板二:\(bfs\)算法,时间复杂度\(O(n^3)\)

#include<bits/stdc++.h>
#define LL long long
#define PII pair<int,int>
using namespace std;

const int maxn=410;
const LL inf=0x3f3f3f3f3f3f3f3f;

int n,m,e;

int link_x[maxn],link_y[maxn];
int que[maxn<<1],top,fail,pre[maxn];
LL g[maxn][maxn],hx[maxn],hy[maxn],slk[maxn];
bool visx[maxn],visy[maxn];

void init(){
    for(int i=1;i<=n;i++){
        link_x[i]=link_y[i]=0;
        visy[i] = false;
    }
    for(int i=1;i<=n;i++){
        hx[i]=0;
        for(int j=1;j<=n;j++){
            if(hx[i]<g[i][j]) hx[i]=g[i][j];
        }
    }
}

int check(int i){
    visx[i]=true;
    if(link_x[i]){
        que[fail++]=link_x[i];
        return visy[link_x[i]]=true;
    }
    while(i){
        link_x[i]=pre[i];
        swap(i,link_y[pre[i]]);
    }
    return 0;
}

void bfs(int s){
    for(int i=1;i<=n;i++){
        slk[i]=inf;
        visx[i]=visy[i]=false;
    }
    top=0; 
    fail=1;
    que[0]=s;
    visy[s]=true;
    while(1){
        LL d;
        while(top<fail){
            for(int i=1,j=que[top++];i<=n;i++){
                if(!visx[i] && slk[i]>=(d=hx[i]+hy[j]-g[i][j])){
                    pre[i]=j;
                    if(d) slk[i]=d;
                    else if(!check(i)) return;
                }
            }
        }
        d=inf;
        for(int i=1;i<=n;i++){
            if(!visx[i] && d>slk[i]) d=slk[i];
        }
        for(int i=1;i<=n;i++){
            if(visx[i]) hx[i]+=d;
            else slk[i]-=d;
            if(visy[i]) hy[i]-=d;
        }
        for(int i=1;i<=n;i++){
            if(!visx[i] && !slk[i] && !check(i)) return;
        }
    }
}
    
int main(){
    scanf("%d %d %d",&n,&m,&e);
    int nn=n;
    n=max(n,m);
    while(e--){
        int u,v;
        LL w;
        scanf("%d %d %lld",&u,&v,&w);
        g[u][v]=w;
    }
    init();
    for(int i=1;i<=n;i++) bfs(i);
    LL ans=0;
    for(int i=1;i<=nn;i++) ans+=g[i][link_x[i]];
    printf("%lld\n",ans);
    for(int i=1;i<nn;i++){
        if(g[i][link_x[i]]==0) link_x[i]=0;
        printf("%d ",link_x[i]);
    }
    if(g[nn][link_x[nn]]==0) link_x[nn]=0;
    printf("%d\n",link_x[nn]);
}
posted @ 2020-11-09 18:27  fxq1304  阅读(84)  评论(0编辑  收藏  举报