带花树模板,用来解决一般图的最大匹配。(可以是带权图)
#include<bits/stdc++.h>
using namespace std;
struct Blossom_algorithm
{
typedef long long s64;
const static int INF = 2147483647;
const static int MaxN = 400;
const static int MaxM = 79800;
template <class T>
inline void tension(T &a, const T &b)
{
if (b < a)
a = b;
}
template <class T>
inline void relax(T &a, const T &b)
{
if (b > a)
a = b;
}
template <class T>
inline int size(const T &a)
{
return (int)a.size();
}
const static int MaxNX = MaxN + MaxN;
struct edge
{
int v, u, w;
edge(){}
edge(const int &_v, const int &_u, const int &_w)
: v(_v), u(_u), w(_w){}
};
int n;
edge mat[MaxNX + 1][MaxNX + 1];
int n_matches;
s64 tot_weight;
int mate[MaxNX + 1];//mate[i]表示i的另一个匹配点,0代表未匹配
int lab[MaxNX + 1];
int q_n, q[MaxN];
int fa[MaxNX + 1], col[MaxNX + 1];
int slackv[MaxNX + 1];
int n_x;
int bel[MaxNX + 1], blofrom[MaxNX + 1][MaxN + 1];
vector<int> bloch[MaxNX + 1];
inline int e_delta(const edge &e) // does not work inside blossoms
{
return lab[e.v] + lab[e.u] - mat[e.v][e.u].w * 2;
}
inline void update_slackv(int v, int x)
{
if (!slackv[x] || e_delta(mat[v][x]) < e_delta(mat[slackv[x]][x]))
slackv[x] = v;
}
inline void calc_slackv(int x)
{
slackv[x] = 0;
for (int v = 1; v <= n; v++)
if (mat[v][x].w > 0 && bel[v] != x && col[bel[v]] == 0)
update_slackv(v, x);
}
inline void q_push(int x)
{
if (x <= n)
q[q_n++] = x;
else
{
for (int i = 0; i < size(bloch[x]); i++)
q_push(bloch[x][i]);
}
}
inline void set_mate(int xv, int xu)
{
mate[xv] = mat[xv][xu].u;
if (xv > n)
{
edge e = mat[xv][xu];
int xr = blofrom[xv][e.v];
int pr = find(bloch[xv].begin(), bloch[xv].end(), xr) - bloch[xv].begin();
if (pr % 2 == 1)
{
reverse(bloch[xv].begin() + 1, bloch[xv].end());
pr = size(bloch[xv]) - pr;
}
for (int i = 0; i < pr; i++)
set_mate(bloch[xv][i], bloch[xv][i ^ 1]);
set_mate(xr, xu);
rotate(bloch[xv].begin(), bloch[xv].begin() + pr, bloch[xv].end());
}
}
inline void set_bel(int x, int b)
{
bel[x] = b;
if (x > n)
{
for (int i = 0; i < size(bloch[x]); i++)
set_bel(bloch[x][i], b);
}
}
inline void augment(int xv, int xu)
{
while (true)
{
int xnu = bel[mate[xv]];
set_mate(xv, xu);
if (!xnu)
return;
set_mate(xnu, bel[fa[xnu]]);
xv = bel[fa[xnu]], xu = xnu;
}
}
inline int get_lca(int xv, int xu)
{
static bool book[MaxNX + 1];
for (int x = 1; x <= n_x; x++)
book[x] = false;
while (xv || xu)
{
if (xv)
{
if (book[xv])
return xv;
book[xv] = true;
xv = bel[mate[xv]];
if (xv)
xv = bel[fa[xv]];
}
swap(xv, xu);
}
return 0;
}
inline void add_blossom(int xv, int xa, int xu)
{
int b = n + 1;
while (b <= n_x && bel[b])
b++;
if (b > n_x)
n_x++;
lab[b] = 0;
col[b] = 0;
mate[b] = mate[xa];
bloch[b].clear();
bloch[b].push_back(xa);
for (int x = xv; x != xa; x = bel[fa[bel[mate[x]]]])
bloch[b].push_back(x), bloch[b].push_back(bel[mate[x]]), q_push(bel[mate[x]]);
reverse(bloch[b].begin() + 1, bloch[b].end());
for (int x = xu; x != xa; x = bel[fa[bel[mate[x]]]])
bloch[b].push_back(x), bloch[b].push_back(bel[mate[x]]), q_push(bel[mate[x]]);
set_bel(b, b);
for (int x = 1; x <= n_x; x++)
{
mat[b][x].w = mat[x][b].w = 0;
blofrom[b][x] = 0;
}
for (int i = 0; i < size(bloch[b]); i++)
{
int xs = bloch[b][i];
for (int x = 1; x <= n_x; x++)
if (mat[b][x].w == 0 || e_delta(mat[xs][x]) < e_delta(mat[b][x]))
mat[b][x] = mat[xs][x], mat[x][b] = mat[x][xs];
for (int x = 1; x <= n_x; x++)
if (blofrom[xs][x])
blofrom[b][x] = xs;
}
calc_slackv(b);
}
inline void expand_blossom1(int b) // lab[b] == 1
{
for (int i = 0; i < size(bloch[b]); i++)
set_bel(bloch[b][i], bloch[b][i]);
int xr = blofrom[b][mat[b][fa[b]].v];
int pr = find(bloch[b].begin(), bloch[b].end(), xr) - bloch[b].begin();
if (pr % 2 == 1)
{
reverse(bloch[b].begin() + 1, bloch[b].end());
pr = size(bloch[b]) - pr;
}
for (int i = 0; i < pr; i += 2)
{
int xs = bloch[b][i], xns = bloch[b][i + 1];
fa[xs] = mat[xns][xs].v;
col[xs] = 1, col[xns] = 0;
slackv[xs] = 0, calc_slackv(xns);
q_push(xns);
}
col[xr] = 1;
fa[xr] = fa[b];
for (int i = pr + 1; i < size(bloch[b]); i++)
{
int xs = bloch[b][i];
col[xs] = -1;
calc_slackv(xs);
}
bel[b] = 0;
}
inline void expand_blossom_final(int b) // at the final stage
{
for (int i = 0; i < size(bloch[b]); i++)
{
if (bloch[b][i] > n && lab[bloch[b][i]] == 0)
expand_blossom_final(bloch[b][i]);
else
set_bel(bloch[b][i], bloch[b][i]);
}
bel[b] = 0;
}
inline bool on_found_edge(const edge &e)
{
int xv = bel[e.v], xu = bel[e.u];
if (col[xu] == -1)
{
int nv = bel[mate[xu]];
fa[xu] = e.v;
col[xu] = 1, col[nv] = 0;
slackv[xu] = slackv[nv] = 0;
q_push(nv);
}
else if (col[xu] == 0)
{
int xa = get_lca(xv, xu);
if (!xa)
{
augment(xv, xu), augment(xu, xv);
for (int b = n + 1; b <= n_x; b++)
if (bel[b] == b && lab[b] == 0)
expand_blossom_final(b);
return true;
}
else
add_blossom(xv, xa, xu);
}
return false;
}
bool match()
{
for (int x = 1; x <= n_x; x++)
col[x] = -1, slackv[x] = 0;
q_n = 0;
for (int x = 1; x <= n_x; x++)
if (bel[x] == x && !mate[x])
fa[x] = 0, col[x] = 0, slackv[x] = 0, q_push(x);
if (q_n == 0)
return false;
while (true)
{
for (int i = 0; i < q_n; i++)
{
int v = q[i];
for (int u = 1; u <= n; u++)
if (mat[v][u].w > 0 && bel[v] != bel[u])
{
int d = e_delta(mat[v][u]);
if (d == 0)
{
if (on_found_edge(mat[v][u]))
return true;
}
else if (col[bel[u]] == -1 || col[bel[u]] == 0)
update_slackv(v, bel[u]);
}
}
int d = INF;
for (int v = 1; v <= n; v++)
if (col[bel[v]] == 0)
tension(d, lab[v]);
for (int b = n + 1; b <= n_x; b++)
if (bel[b] == b && col[b] == 1)
tension(d, lab[b] / 2);
for (int x = 1; x <= n_x; x++)
if (bel[x] == x && slackv[x])
{
if (col[x] == -1)
tension(d, e_delta(mat[slackv[x]][x]));
else if (col[x] == 0)
tension(d, e_delta(mat[slackv[x]][x]) / 2);
}
for (int v = 1; v <= n; v++)
{
if (col[bel[v]] == 0)
lab[v] -= d;
else if (col[bel[v]] == 1)
lab[v] += d;
}
for (int b = n + 1; b <= n_x; b++)
if (bel[b] == b)
{
if (col[bel[b]] == 0)
lab[b] += d * 2;
else if (col[bel[b]] == 1)
lab[b] -= d * 2;
}
q_n = 0;
for (int v = 1; v <= n; v++)
if (lab[v] == 0) // all unmatched vertices' labels are zero! cheers!
return false;
for (int x = 1; x <= n_x; x++)
if (bel[x] == x && slackv[x] && bel[slackv[x]] != x && e_delta(mat[slackv[x]][x]) == 0)
{
if (on_found_edge(mat[slackv[x]][x]))
return true;
}
for (int b = n + 1; b <= n_x; b++)
if (bel[b] == b && col[b] == 1 && lab[b] == 0)
expand_blossom1(b);
}
return false;
}
void init(int n)
{
this->n=n;
for (int v = 1; v <= n; v++)
for (int u = 1; u <= n; u++)
mat[v][u] = edge(v, u, 0);
}
void addedge(int u,int v,int w)
{
mat[u][v].w=mat[v][u].w=w;
}
void calc_max_weight_match()
{
for (int v = 1; v <= n; v++)
mate[v] = 0;
n_x = n;
n_matches = 0;
tot_weight = 0;
bel[0] = 0;
for (int v = 1; v <= n; v++)
bel[v] = v, bloch[v].clear();
for (int v = 1; v <= n; v++)
for (int u = 1; u <= n; u++)
blofrom[v][u] = v == u ? v : 0;
int w_max = 0;
for (int v = 1; v <= n; v++)
for (int u = 1; u <= n; u++)
relax(w_max, mat[v][u].w);
for (int v = 1; v <= n; v++)
lab[v] = w_max;
while (match())
n_matches++;
for (int v = 1; v <= n; v++)
if (mate[v] && mate[v] < v)
tot_weight += mat[v][mate[v]].w;
}
}BA;
int main()
{
BA.init(n);//初始化
BA.addedge(u,v,w)//加边操作
BA.calc_max_weight_match();//匹配
printf("%lld\n", BA.tot_weight);//输出最大匹配
for (int v = 1; v <= BA.n; v++)
printf("%d ",BA.mate[v]);//输出另一个匹配点
return 0;
}