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 |
Re:发两个注意事项~没做对的同学可以参考一下。In Reply To:发两个注意事项~没做对的同学可以参考一下。 Posted by:Moon_1st at 2011-04-26 15:14:16 > 题目大意:给定一个无向图,求它的最大密度子图。 > > 到目前做过的所有网络流的题,这个应该是最难的一个,并不是因为它的编码,而 > 是分析和建模的过程。最小割模型之所以让人觉得难,是因为它并不像简单的求最 > 大流那样直观,而是牵扯到边割集的性质,有些问题要最大化某个量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; > } 多谢大神帮助,终于AC了,您发的帖子真心很用心,而且对我帮助很大。 Followed by: Post your reply here: |
All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator