Online Judge | Problem Set | Authors | Online Contests | User | ||||||
---|---|---|---|---|---|---|---|---|---|---|
Web Board Home Page F.A.Qs Statistical Charts | Current Contest Past Contests Scheduled Contests Award Contest |
发两个注意事项~没做对的同学可以参考一下。题目大意:给定一个无向图,求它的最大密度子图。 到目前做过的所有网络流的题,这个应该是最难的一个,并不是因为它的编码,而 是分析和建模的过程。最小割模型之所以让人觉得难,是因为它并不像简单的求最 大流那样直观,而是牵扯到边割集的性质,有些问题要最大化某个量x,假设最小割 为y,那么如果从数学上可以证明x+y==c(c是个常数)的话,只要让y最小化,即 求出原图的最小割,用c-y即是x可以取得的最大值。这种题目关键在于数学建模和 对问题的透彻分析,把握量和量之间的关系,只有做到对网络流的性质了如指掌才 有可能顺利解决。 题目的具体解法大家可以参考胡伯涛的论文《最小割模型在信息学竞赛中的应用》, 论文中给出了详细的分析。 这里再补充一点编程时需要注意的地方:这个题目是利用分数规划进行二分求解的, 但这个问题的分数规划和我之前的见过的很多分数规划是不同的,之前的分数规划表 达式很多都是在给定区间内只有一个零点的单调函数。但这个题目不同,因为 MiniCut=U*n-Maxmize{f(n)},而MiniCut& lt;=U*n是恒成立的,所以 Maxmize{f(n)}>=0恒成立,及Maxmize{f(n)}函数会先递减,然后一直为0,我们的目 标是找出第一个零点。所以二分应该这么写: while(r-l >= 1.0/n/n) { mid = (l+r) / 2; BuildGraph(); Cut = Max_flow(s, t); tmp = (U*n-Cut) / 2; if(tmp > eps) l = mid; else r = mid; } 而不能当找出一个零点时直接break。 第二个需要注意的地方: 对于这种输入数据: 3 3 1 2 2 3 3 1 最后一次网络流的运行会使所有从s出发的边满流,这时候子图的顶点数为0,结果 输出为0,不符合题意。但是由于误差最多不会超过1/(n*n),所以取l再做一次网络 流然后查解输出就可以了(解就是所有从s通过最后的参量网络可达的顶点——因为 这保证了不走割边,这就和论文中的讲解一致了)。 附代码: #include <iostream> #include <cstdio> #include <cstring> using namespace std; const int N = 110; const int M = 1010; const double INF = 1e8; const double eps = 1e-7; struct node { int u, v; double c; }e[M*4]; int s, t, n, m, tot, d[N], que[N], h[N], level[N], nxt[M*4]; bool visit[N], map[N][N]; double min(double x, double y) { return x < y ? x : y; } void add(int u, int v, double c) { e[tot].u = u; e[tot].v = v; e[tot].c = c; nxt[tot] = h[u]; h[u] = tot++; } bool bfs(int s, int t) { int u, v, head, tail, p; head = tail = 0; que[0] = s; memset(level, 0, sizeof(level)); memset(visit, false, sizeof(visit)); level[s] = 0; visit[s] = true; while(head <= tail) { u = que[head++]; p = h[u]; while(p != -1) { v = e[p].v; if(!visit[v] && e[p].c>0) { level[v] = level[u]+1; visit[v] = true; que[++tail] = v; } if(visit[t]) return true; p = nxt[p]; } } return false; } double dinic_dfs(double delta, int u) { int p, v; double tmp, sum = 0.0; if(u == t) return delta; p = h[u]; while(p != -1) { v = e[p].v; if(level[u]+1==level[v] && e[p].c>0) { tmp = dinic_dfs(min(delta, e[p].c), v); sum += tmp; delta -= tmp; e[p].c -= tmp; e[p^1].c += tmp; } p = nxt[p]; } return sum; } double Max_flow(int s, int t) { double ans = 0.0; while(bfs(s, t)) ans += dinic_dfs(INF, s); return ans; } void dfs(int u) { int p = h[u]; visit[u] = true; while(p != -1) { if(e[p].c>eps && !visit[e[p].v]) dfs(e[p].v); p = nxt[p]; } } int main() { int i, j, a, b, ans; double l, r, mid, U, Cut, tmp; while(scanf("%d%d", &n, &m) != EOF) { memset(map, false, sizeof(map)); memset(d, 0, sizeof(d)); for(i = 0; i < m; i++) { scanf("%d%d", &a, &b); map[a][b] = true; d[a]++; d[b]++; } if(m == 0) { printf("1\n1\n"); return 0; } l = 0.0; r = m; s = 0; t = n+1; U = m; while(r-l >= 1.0/n/n) { mid = (l+r) / 2; tot = 0; memset(h, -1, sizeof(h)); for(i = 1; i <= n; i++) { add(s, i, U); add(i, s, 0.0); add(i, t, U+2*mid-(double)d[i]); add(t, i, 0.0); } for(i = 1; i <= n; i++) for(j = 1; j <= n; j++) if(map[i][j]) { add(i, j, 1.0); add(j, i, 1.0); } Cut = Max_flow(s, t); tmp = (U*n-Cut) / 2; if(tmp > eps) l = mid; else r = mid; } tot = 0; memset(h, -1, sizeof(h)); for(i = 1; i <= n; i++) { add(s, i, U); add(i, s, 0.0); add(i, t, U+2*l-(double)d[i]); add(t, i, 0.0); } for(i = 1; i <= n; i++) for(j = 1; j <= n; j++) if(map[i][j]) { add(i, j, 1.0); add(j, i, 1.0); } Cut = Max_flow(s, t); ans = 0; memset(visit, false, sizeof(visit)); dfs(s); for(ans=0,i=1; i <= n; i++) if(visit[i]) ans++; printf("%d\n", ans); for(i = 1; i <= n; i++) if(visit[i]) printf("%d\n", i); } return 0; } Followed by:
Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator