题意是已知一个无向图所有点对间的最小割,构造一个合法的原图。
看了题解得知有个叫Gomory-Hu tree的东西,即最小割树。解题要点是,你要知道一个图的所有点对最小割,一定能用一棵树做到。于是我们的目标变为构造这样一棵树。
我们可以用分治法,不断把当前点集划分为两个点集,其中两个点集的点之间流量是当前最小,不断分治直到集合只剩一个点。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = ;
int n;
int w[maxn][maxn];
vector<int> adj[maxn];
vector<int> adjw[maxn];
bool ok = ;
void fun(set<int> s){
if(s.size()<)return;
int MIN = ;
int U,V;
for(int u:s){
for(int v:s){
if(u==v)continue;
if(w[u][v]<MIN){
MIN = w[u][v];
U=u;
V=v;
}
}
}
set<int> uSet;
set<int> vSet;
uSet.insert(U);
vSet.insert(V);
for(int q:s){
if(q==U || q==V)continue;
if(w[U][q]==MIN){
vSet.insert(q);
}else{
uSet.insert(q);
}
}
for(int u:uSet){
for(int v:vSet){
if(w[u][v]!=MIN){
ok=;
}
}
}
adj[U].push_back(V);
adjw[U].push_back(MIN);
fun(uSet);
fun(vSet);
}
class AllGraphCuts{
public:
vector<int> findGraph(vector<int> x){
n = sqrt(x.size());
int MAX = -;
set<int> oriSet;
for(int i=;i<n;i++){
for(int j=;j<n;j++){
w[i][j] = x[i*n+j];
if(i==j){
if(w[i][j]){
ok=;
}
continue;
}
if(j<i){
if(w[i][j]!=w[j][i])ok=;
}
if(w[i][j]>MAX){
MAX = w[i][j];
}
}
oriSet.insert(i);
}
fun(oriSet);
vector<int> ans;
if(!ok){
cout<<"-1"<<endl;
ans.push_back(-);
return ans;
}
for(int i=;i<n;i++){
//w*n*n + i*n + j
for(int k=;k<adj[i].size();k++){
int j = adj[i][k];
int ww = adjw[i][k];
ans.push_back(ww*n*n+i*n+j);
}
}
return ans;
}
};