频道栏目
首页 > 资讯 > 其他 > 正文

bnu 51644 Whalyzh's Problem(网络流,最大密度图) (北师16校赛)

16-07-04        来源:[db:作者]  
收藏   我要投稿

 

很久以前,当whalyzh同学是一个萌新的时候,遇到了这么一个问题:

给定长为n的序列B,构造一个只有0和1的长为n的序列A,使得\sum_{i=0}^{n-1}{A[i] \times B[i]}的值最大。

小Q同学想了一秒钟之后说:这不是一眼题么?然后whalyzh同学瞬间就会了。

过了几天,当whalyzh同学还是一个萌新的时候,遇到了这么一个问题:

给定n阶方阵B,构造一个只有0和1的1 \times n的向量A,使得ABA^T=\sum_{i=0}^{n-1}\sum_{j=0}^{n-1}{A[i] \times B[i][j] \times A[j]}的值最大。

小Q同学想了一分钟之后说:这不是一眼题么?然后whalyzh同学瞬间就会了。

又过了几天,当whalyzh仍然是一个萌新的时候,遇到了这么一个问题:

给定n阶方阵B,构造一个只有0和1的1 \times n的向量A,使得(ABA^T-\sum_{i=0}^{n-1}{A[i] \times B[i][i])/\sum_{i=0}^{n-1}{A[i]}的值最大。

小Q同学想了一小时之后说:不能总是问我,你得自己去思考。然后whalyzh同学瞬间就懵逼了。

即使到现在,whalyzh同学仍然百思不得其解,希望你能帮他解决这个问题。

请注意,在这个问题中,规定0/0=0

 

Input

第一行是一个正整数T(\leq 50),表示测试数据的组数,

对于每组测试数据,

第一行是一个整数n(1 \leq n \leq 100),表示方阵的大小,

接下来n行,每行n个整数b[i][j](0 \leq b[i][j] \leq 10),表示方阵中的数。

 

Output

对于每组测试数据,输出所求的最大值,答案精确到小数点后五位。

 

Sample Input

1
3
0 1 0
1 2 4
1 3 2

Sample Output

3.50000

Hint

对于样例,令A[0]=0,A[1]=1,A[2]=1,可取得最大值7/2=3.50000

 

Source

第十四届北京师范大学程序设计竞赛决赛

Author

hwq1352249

 

题目大意:

给出一个矩阵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
#include
#include
#include
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;
}


 

相关TAG标签
上一篇:LeetCode Gas Station
下一篇:vs与opencv配置原理
相关文章
图文推荐

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站