模板 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]);
}