传送门:https://nanti.jisuanke.com/t/15549
一道论文题,具体求解过程就不详将了(毕竟本人太菜了)
推荐看《最小割模型在信息学竞赛中的应用》这本论文,很好的诠释了最大密度子图在网络流中的应用
题解:网络流+最大密度子图
c(s,v)=U
c(v,t)=U+4ng-2g-du
c(u,v)=mp[u][v]+2g
其中du为与点u相连的边的总权值,g为二分的密度值,U为一个足够大的正数
#include<bits/stdc++.h>
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
const double eps = 1e-8;
const int MX = 400 + 5;
int n, m, a[MX];
double mp[MX][MX];
const int inf = 0x3f3f3f3f;
const int MXE = 4 * MX * MX;
struct MaxFlow {
struct Edge {
int v, nxt;
double w;
} edge[MXE];
int tot, num, s, t;
int head[MX];
void init() {
memset(head, -1, sizeof(head));
tot = 0;
}
void add(int u, int v, double w) {
edge[tot].v = v;
edge[tot].w = w;
edge[tot].nxt = head[u];
head[u] = tot++;
edge[tot].v = u;
edge[tot].w = 0;
edge[tot].nxt = head[v];
head[v] = tot++;
}
int d[MX], vis[MX], gap[MX];
void bfs() {
memset(d, 0, sizeof(d));
memset(gap, 0, sizeof(gap));
memset(vis, 0, sizeof(vis));
queue<int>q;
q.push(t);
vis[t] = 1;
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v;
if (!vis[v]) {
d[v] = d[u] + 1;
gap[d[v]]++;
q.push(v);
vis[v] = 1;
}
}
}
}
int last[MX];
double dfs(int u, double f) {
if (u == t) return f;
double sap = 0;
for (int i = last[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v;
if (edge[i].w > 0 && d[u] == d[v] + 1) {
last[u] = i;
double tmp = dfs(v, min(f - sap, edge[i].w));
edge[i].w -= tmp;
edge[i ^ 1].w += tmp;
sap += tmp;
if (sap == f) return sap;
}
}
if (d[s] >= num) return sap;
if (!(--gap[d[u]])) d[s] = num;
++gap[++d[u]];
last[u] = head[u];
return sap;
}
double solve(int st, int ed, int n) {
double flow = 0;
num = n;
s = st;
t = ed;
bfs();
memcpy(last, head, sizeof(head));
while (d[s] < num) flow += dfs(s, inf);
return flow;
}
} F;
double du[MX];
bool ok(double g) {
F.init();
int s = 0, t = n + 1;
double U = 0;
for (int i = 1; i <= n; i++) {
du[i] = 4 * n * g - 2 * g;
for (int j = 1; j <= n; j++)
if (i != j)du[i] -= mp[i][j] + 2 * g;
U = min(U, du[i]);
}
U = fabs(U);
for (int i = 1; i <= n; i++)
for (int j = 1; j < i; j++) {
F.add(i, j, mp[i][j] + 2 * g);
F.add(j, i, mp[i][j] + 2 * g);
}
for (int i = 1; i <= n; i++) {
F.add(s, i, a[i] ? inf : U);
F.add(i, t, du[i] + U);
}
double ans = U * n - F.solve(s, t, n + 2);
return ans > eps;
}
int main() {
// freopen("in.txt","r",stdin);
while (~scanf("%d%d", &n, &m)) {
memset(mp, 0, sizeof(mp));
double l = 0, r = 0;
for (int i = 1; i <= m; i++) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
mp[u][v] = mp[v][u] = w;
r += w;
}
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
for (int i = 0; i < 50; i++) {
double mid = (l + r) / 2;
if (ok(mid)) l = mid;
else r = mid;
}
printf("%.6f\n", r);
}
return 0;
}