//黑白二着色-bicoloring(判断是否为二分图)
int color[maxn];
bool bipartite(int u){
for(int i = 0; i < g[u].size(); i++){
int v = g[u][i];
if(color[u] == color[v]) return false;
if(!color[v]){
color[v] = 3 - color[u];
if(!bipartite(v)) return false;
}
}
return true;
}
//二分图的最大匹配
void dfs(int x){
for(int i = 0; i < g[x].size(); i++){
int y = g[x][i];
if(!path[y]){
path[y] = 1;
if(c[y] == -1 || dfs(c[y])){
c[y] = x;
return true;
}
}
}
return false;
}
int main() {
int ans = 0;
memset(c, -1, sizeof(c));
for(int i=0; i < num_left; i++){
memset(path, 0, sizeof(path));
if(dfs(i)) ans++;
}
}
//二分图的最佳完美匹配(KM算法)
int W[maxn][maxn],n;
int Lx[maxn],Ly[maxn];
int left[maxn];
bool S[maxn],T[maxn];
bool match(int i){
S[i]=true;
for(int j=1;j<=n;j++) if(Lx[i]+Ly[j]==W[i][j]&&!T[j]){
T[j]=true;
if(!left[j]||match(left[j])){
left[j]=i;
return true;
}
}
return false;
}
void update(){
int a=1<<30;
for(int i=1;i<=n;i++) if(S[i])
for(int j=1;j<=n;j++) if(!T[j])
a=min(Lx[i]+Ly[j]-W[i][j]);
for(int i=1;i<=n;i++){
if(S[i]) Lx[i]-=a;
if(L[i]) Ly[i]+=a;
}
}
void KM(){
for(int i=1;i<=n;i++){
left[i]=Lx[i]=Ly[i]=0;
for(int j=1;j<=n;j++)
Lx[i]=max(Lx[i],W[i][j]);
}
for(int i=1;i<=n;i++){
for(;;){
for(int j=1;j<=n;j++) S[i]=T[j]=false;
if(match(i)) break; else update();
}
}
}