Online JudgeProblem SetAuthorsOnline ContestsUser
Web Board
Home Page
F.A.Qs
Statistical Charts
Problems
Submit Problem
Online Status
Prob.ID:
Register
Update your info
Authors ranklist
Current Contest
Past Contests
Scheduled Contests
Award Contest
User ID:
Password:
  Register

发两个注意事项~没做对的同学可以参考一下。

Posted by Moon_1st at 2011-04-26 15:14:16 on Problem 3155 and last updated at 2011-04-26 15:15:22
题目大意:给定一个无向图,求它的最大密度子图。

到目前做过的所有网络流的题,这个应该是最难的一个,并不是因为它的编码,而
是分析和建模的过程。最小割模型之所以让人觉得难,是因为它并不像简单的求最
大流那样直观,而是牵扯到边割集的性质,有些问题要最大化某个量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:
User ID:
Password:
Title:

Content:

Home Page   Go Back  To top


All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator