uoj80(KM算法模板)

题目链接

http://uoj.ac/problem/80

题解

二分图最大权匹配可以用费用流求解,但是当图比较稠密时,费用流的效率就会变得十分低下,因而使用 KM 算法代替

KM 算法本用于解决二分图完美匹配问题,所以在构造图的时候需要将图补成一个左右节点相同的完全二分图,即补上一些虚点和虚边使得完美匹配一定存在,且最大完美匹配等于原图的最大权匹配

然后复杂度是 $O(n^3)$ ,其实速度也不是很快,仅适用于完全图




代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/*
*         ┏┓    ┏┓
*         ┏┛┗━━━━━━━┛┗━━━┓
*         ┃       ┃  
*         ┃   ━    ┃
*         ┃ >   < ┃
*         ┃       ┃
*         ┃... ⌒ ...  ┃
*         ┃ ┃
*         ┗━┓ ┏━┛
*          ┃ ┃ Code is far away from bug with the animal protecting          
*          ┃ ┃ 神兽保佑,代码无bug
*          ┃ ┃           
*          ┃ ┃       
*          ┃ ┃
*          ┃ ┃           
*          ┃ ┗━━━┓
*          ┃ ┣┓
*          ┃ ┏┛
*          ┗┓┓┏━━━━━━━━┳┓┏┛
*           ┃┫┫ ┃┫┫
*           ┗┻┛ ┗┻┛
*/

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<set>
#include<bitset>
#include<assert.h>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define eps 1e-8
#define succ(x) (1<<x)
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define mid (x+y>>1)
#define NM 405
#define nm 200005
#define pi 3.1415926535897931
#define mp(x,y) make_pair(x,y)
using namespace std;
const int inf=1e9;
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}



int n,m,p,_x,_y,a[NM][NM];
int pre[NM],match[NM],_match[NM];
int b[NM],lx[NM],ly[NM];
bool v[NM];
ll ans;


void km(int n){
inc(i,1,n){
int y=0;
mem(v);match[0]=i;
inc(j,1,n)b[j]=inf;
for(int t;match[y];y=t){
int s=inf,x=match[y];v[y]++;
inc(j,1,n)if(!v[j]){
if(b[j]>lx[x]+ly[j]-a[x][j])b[j]=lx[x]+ly[j]-a[x][j],pre[j]=y;
if(s>b[j])s=b[j],t=j;
}
inc(j,0,n)if(v[j])lx[match[j]]-=s,ly[j]+=s;else b[j]-=s;
}
for(;y;y=pre[y])match[y]=match[pre[y]];
}
}

int main(){
n=read();m=read();p=read();
while(p--){
_x=read();_y=read();a[_x][_y]=read();
}
km(max(n,m));
inc(j,1,m)if(match[j]){
ans+=ly[j]+lx[match[j]];
if(a[match[j]][j])_match[match[j]]=j;
}
printf("%lld\n",ans);
inc(i,1,n)printf("%d%c",_match[i]," \n"[i==n]);
return 0;
}