坤M算法有它的局限性:要求带权最大匹配一定是完备匹配
但是效率高啊:坤M算法 Θ ( n 3 ) \Theta(n^3) Θ(n3),费用流 Θ ( 能 过 ) \Theta(能过) Θ(能过)
奇奇怪怪的定义:
结论:当每个相等子图完备匹配时,二分图有最大匹配
证明:对于二分图 ∑ i ∈ S A , j ∈ S B A i + B j ≥ ∑ i ∈ S A , j ∈ S B w i ↔ j \sum_{i\in S_A,j\in S_B}A_i+B_j\geq\sum_{i\in S_A,j\in S_B}w_{i\leftrightarrow j} ∑i∈SA,j∈SBAi+Bj≥∑i∈SA,j∈SBwi↔j,而现在边权和已经抵到最大值即顶标之和了,不能再大
算法:
分配顶标,左部令为边权( A i = max { w i ↔ j } A_i=\max\{w_{i\leftrightarrow j}\} Ai=max{wi↔j}),右部令为零
修改顶标,找不到相等子图的时候就修改
修改顶标时不会改变现有匹配的权值,算法具有正确性
修改顶标直到找到完备匹配
考虑修改顶标
发现DFS时左部到右部走的都是非匹配边,右部到左部走的都是匹配边
而走匹配边无需修改顶标
考虑走非匹配边的修改顶标
若从左部点走到右部点,以前能访问,现在仍能访问,则修改没有作用
而若以前右部点不在匹配(记为 T T T)中,现在在,则需要考虑加入此边
即在左部点 i ∈ T i\in T i∈T,右部点 j ∉ T j\notin T j∈/T(可能是众点中的一个),加入这条边,构造出相等子图的边 A i + B j = w i ↔ j A_i+B_j=w_{i\leftrightarrow j} Ai+Bj=wi↔j
而原来 A i + B j ≥ w i ↔ j A_i+B_j\geq w_{i\leftrightarrow j} Ai+Bj≥wi↔j,因此减少 A i + B j − w i ↔ j A_i+B_j-w_{i\leftrightarrow j} Ai+Bj−wi↔j,且要求它最小
注意,改变值的是交错树中顶标,非交错树中的顶标不变
板题
不知为何会WA但是是照着标程打的代码
#include
using namespace std;
#define in Read()
int in{
int i=0,f=1;char ch=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') ch=getchar();
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
typedef long long ll;
const int N=505;
const int INF=2147483647;
int n,m;
int w[N][N],mat[N];
int la[N],lb[N],upd[N],delta;
bool va[N],vb[N];
// upd for updating delta, which if b\notin T
bool DFS(int u){
va[u]=true;
for(int v=1;v<=n;++v){
if(!vb[v])
if(la[u]+lb[v]-w[u][v]) upd[v]=min(upd[v],la[u]+lb[v]-w[u][u]);
else{
vb[v]=true;
if(!mat[v]||DFS(mat[v])){
mat[v]=u;
return true;
}
}
}
return false;
}
ll KM(){
for(int i=1;i<=n;++i){
la[i]=-INF;
lb[i]=0;
for(int j=1;j<=n;++j)
la[i]=max(la[i],w[i][j]);
}
for(int i=1;i<=n;++i)
// Until get the match
// modify topmark each time
while(true){
memset(va,0,sizeof(va));
memset(vb,0,sizeof(vb));
for(int j=1;j<=n;++j) upd[j]=INF;
if(DFS(i)) break;
for(int j=1;j<=n;++j)
if(!vb[j]) delta=min(delta,upd[j]);
for(int j=1;j<=n;++j){
if(va[j]) la[j]-=delta;
if(vb[j]) lb[j]+=delta;
}
}
ll ans=0;
for(int i=1;i<=n;++i) ans+=w[mat[i]][i];
return ans;
}
int main(){
n=in,m=in;
for(int i=1;i<=n;++i)
for(int j=1;j<=n;++j)
w[i][j]=-INF;
for(int i=1;i<=n;++i){
int u=in,v=in,val=in;
w[u][v]=max(w[u][v],val);
}
printf("%lld\n",KM());
for(int i=1;i<=n;++i) printf("%d ",mat[i]);
return 0;
}
优秀的BFS不想码了
这DFS就够恶心了
再加上我看不懂yyr巨巨的代码
好吧,坤M就是这样