struct hungary{
int n,m; //X集和Y集的点数
int match[M]; //匹配
bool vis[M]; //是否在增广路上
vector<int>g[M]; //邻接表
void init(int _n,int _m){
n=_n,m=_m,clr(match,-1,m);
for(int i=0;i<n;i++) g[i].clear();
}
void insert(int u,int v){g[u].push_back(v);}
bool augment(int u){//增广
for(int i=0,v;i<g[u].size();i++){
if(!vis[v=g[u][i]]){
vis[v]=1;
if(match[v]==-1 || augment(match[v])){
match[v]=u;
return true;
}
}
}
return false;
}
int maxMatch(){
int res=0;
for(int i=0;i<n;i++){
clr(vis,0,m);
if(augment(i)) res++;
}
return res;
}
};
struct KM{//邻接表
typedef int type;
struct edge{
int from,to;
type w;
edge(int u,int v,type _w){from=u,to=v,w=_w;}
};
int n,m; // X/Y集的点数
int match[M]; // 匹配
type lx[M],ly[M],d; // X/Y项标,松弛量
bool vx[M],vy[M]; // X/Y集的点是否在已经访问
vector<edge>edg; // 边表
vector<int>g[M]; // 邻接表
void init(int _n,int _m){
n=_n,m=_m;
clr(match,-1,m),edg.clear();
for(int i=0;i<n;i++) g[i].clear();
}
void insert(int u,int v,type w){
edg.push_back(edge(u,v,w));
g[u].push_back(edg.size()-1);
}
bool augment(int u){// 增广
vx[u]=1;
for(int i=0;i<g[u].size();i++){
edge& e=edg[g[u][i]];
if(vy[e.to]) continue;
if(lx[u]+ly[e.to]==e.w){
vy[e.to]=1;
if(match[e.to]==-1 || augment(match[e.to])){
match[e.to]=u;
return true;
}
}else getmin(d,lx[u]+ly[e.to]-e.w);
}
return false;
}
type maxWeight(){
int i,j;
for(i=0;i<m;i++) ly[i]=0;
for(i=0;i<n;i++){
lx[i]=-INF;
for(j=0;j<g[i].size();j++)
getmax(lx[i],edg[g[i][j]].w);
}
for(i=0;i<n;i++){
for(;;){
clr(vx,0,n),clr(vy,0,m);
d=-1;
if(augment(i)) break;
for(j=0;j<n;j++) if(vx[j]) lx[j]-=d;
for(j=0;j<m;j++) if(vy[j]) ly[j]+=d;
}
}
type res=0;
for(i=0;i<n;i++) res+=lx[i];
for(i=0;i<m;i++) res+=ly[i];
return res;
}
};
struct KM{//邻接矩阵
typedef int type;
int n,m,match[M]; // X/Y集的点数,匹配
type lx[M],ly[M],w[M][M],d;// X/Y项标,松弛量
bool vx[M],vy[M]; // X/Y集的点是否在已经访问
void init(int _n,int _m){
n=_n,m=_m,clr(match,-1,m);
for(int i=0;i<n;i++) for(int j=0;j<m;j++) w[i][j]=-INF;
}
bool augment(int u){//增广
vx[u]=1;
for(int v=0;v<m;v++){
if(vy[v]) continue;
if(lx[u]+ly[v]==w[u][v]){
vy[v]=1;
if(match[v]==-1 || augment(match[v])){
match[v]=u;
return true;
}
}else getmin(d,lx[u]+ly[v]-w[u][v]);
}
return false;
}
type maxWeight(){
int i,j;
for(i=0;i<m;i++) ly[i]=0;
for(i=0;i<n;i++){
lx[i]=-INF;
for(j=0;j<m;j++)
getmax(lx[i],w[i][j]);
}
for(i=0;i<n;i++){
for(;;){
clr(vx,0,n),clr(vy,0,m);
d=-1;
if(augment(i)) break;
for(j=0;j<n;j++) if(vx[j]) lx[j]-=d;
for(j=0;j<m;j++) if(vy[j]) ly[j]+=d;
}
}
type res=0;
for(i=0;i<n;i++) res+=lx[i];
for(i=0;i<m;i++) res+=ly[i];
return res;
}
};