标签:
很久以前,当whalyzh同学是一个萌新的时候,遇到了这么一个问题:
给定长为的序列,构造一个只有0和1的长为的序列,使得的值最大。
小Q同学想了一秒钟之后说:这不是一眼题么?然后whalyzh同学瞬间就会了。
过了几天,当whalyzh同学还是一个萌新的时候,遇到了这么一个问题:
给定阶方阵,构造一个只有0和1的的向量,使得的值最大。
小Q同学想了一分钟之后说:这不是一眼题么?然后whalyzh同学瞬间就会了。
又过了几天,当whalyzh仍然是一个萌新的时候,遇到了这么一个问题:
给定阶方阵,构造一个只有0和1的的向量,使得的值最大。
小Q同学想了一小时之后说:不能总是问我,你得自己去思考。然后whalyzh同学瞬间就懵逼了。
即使到现在,whalyzh同学仍然百思不得其解,希望你能帮他解决这个问题。
请注意,在这个问题中,规定。
第一行是一个正整数,表示测试数据的组数,
对于每组测试数据,
第一行是一个整数,表示方阵的大小,
接下来行,每行个整数,表示方阵中的数。
对于每组测试数据,输出所求的最大值,答案精确到小数点后五位。
1 3 0 1 0 1 2 4 1 3 2
3.50000
对于样例,令,可取得最大值。
题目大意:
给出一个矩阵B(元素小于等于10)和一个由01组成的向量A,能选择其中的B[i][j]当且仅当A[i]=A[j]=1且i!=j,给定B通过A中把一些数置为1来选择B中的数使得B中数的和比上A中1的个数最大。
解题思路:
原问题等价于给定一个n个顶点的图,每两点之间有一条边,边权为1到10,然后从中选出一些点,使的这些点的诱导子图的边权和/点数尽可能大,这是一个最大密度子图问题。
感谢chitanda的代码~
#include<cmath> #include<cstring> #include<cstdio> #include<algorithm> using namespace std; #define N 100 const double eps = 1e-8; const double inf = 1e+8; struct Edge { int v; double w; Edge *x; } *e, *lnk[N * N + 9], E[12 * N * N + 9]; int TT, S, T, n, m, b[N + 9][N + 9]; int g[N * N + 9], h[N * N + 9]; int dcmp(double x) { return (x > +eps) - (x < -eps); } void add(int u, int v, double w) { e->v = v, e->w = w, e->x = lnk[u], lnk[u] = e++; e->v = u, e->w = 0, e->x = lnk[v], lnk[v] = e++; } double sap(int u, double flw) { if (u == T) return flw; double det, sum = .0; for (Edge *p = lnk[u]; p; p = p->x) if (h[u] == h[p->v] + 1 && dcmp(p->w)) { det = sap(p->v, min(p->w, flw - sum)); p->w -= det; E[(p - E) ^ 1].w += det; if (dcmp((sum += det) - flw) == 0) return sum; } if (h[S] >= m) return sum; if (--g[h[u]] == 0) h[S] = m; ++g[++h[u]]; return sum; } bool check(double x) { m = n + n * (n - 1) / 2; S = ++m, T = ++m; e = E; for (int i = 1; i <= m; ++i) lnk[i] = 0; for (int i = 1; i <= n; ++i) add(i, T, x); int cnt = n; double sum = .0; for (int i = 1; i < n; ++i) for (int j = i + 1; j <= n; ++j) { ++cnt; if (b[i][j]) { sum += b[i][j]; add(S, cnt, b[i][j]); } add(cnt, i, inf); add(cnt, j, inf); } g[0] = m; for (int i = 1; i <= m; ++i) g[i] = h[i] = 0; while (h[S] < m) sum -= sap(S, inf); return sum > eps; } int main() { scanf("%d", &TT); while (TT--) { scanf("%d", &n); memset(b, 0, sizeof b); for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) { int x; scanf("%d", &x); if (i < j) b[i][j] += x; if (i > j) b[j][i] += x; } double l = 0, r = 1000, m; while (fabs(r - l) > eps) { m = (l + r) / 2; if (check(m)) l = m; else r = m; } printf("%.5f\n", l); } return 0; }
bnu 51644 Whalyzh's Problem(网络流,最大密度图) (北师16校赛)
标签:
原文地址:http://blog.csdn.net/chat_c/article/details/51263578