zoukankan      html  css  js  c++  java
  • hdu4859 (最大流最小割)

    中文题面不再复述。首先来讲下什么是最小割,假设去掉(割掉)一些边使得一个图不再连通,这些边有很多种删去方法,但每条边都有一个权值(或者说容量),使得这些所有删去的边的容量和最小的情况就称作最小割。学习过最大流可以发现,最大流是取每条增广路上可通过的最大流量,因此最大流量和刚好和最小割取得的容量和相等。题目抽象为模型可知,'E'可看作'.',也可看作'D',假设我们直接套用最大流模板建图,将所有的'.'与源点s相连,将所有的'D'与汇点相连,那么情况如下图:

    如果照上图建图,我们得到的是最小的'.'和'D'相连的数目(即最小海岸线)。然而题上要求的求最长的海岸线。一开始怎么想都不理解怎么转化建模。我们想要求最长的海岸线,就是求最大的'.'和'D'可相邻数,换句话说,就是最小的'.'或'D'相同相邻数。这里介绍一种较为神奇的模型构造法,奇偶建图。由于我们建图时会把相邻的点连接在一起,那么相连的点必然是一奇一偶,为了与这种情况相匹配,我们可以图上的点(i,j)i+j为奇数的'.'与源点s相连,i+j为偶数的'D'与源点相连,i+j为偶数的'D'和i+j为奇数的'D'与汇点相连。这样建图后,源点的'.'对应的汇点连接的至少不会是'D'(因为奇数连接的会是偶数,偶数连接的会是奇数),这样进行最大流最小割求解,得到的刚好就是最少的相同字符的可相邻数,这样我们用恒定不变的总相邻数减去最少相同字符的可相邻数,便可得到最大不同字符相邻数了,即题上要求的最长海岸线。总相邻数可在建图的时候就进行统计。需要注意数据范围,尽管图只有47*47这么大,但是我们需要对外界圈一圈边界也算作海岸线,因此点的范围要到2500的样子。思路明确,具体实现细节看代码。

    #include <stdio.h>
    #include <algorithm>
    #include <string.h>
    #include <queue>
    using namespace std;
    #define oo 0x3f3f3f3f
    struct ad
    {
        int v, next, flow;
    } edge[3000000];
    int head[3000], edge_num, id[110][110], vis[3000];
    int dir[4][2] = { {0, 1}, {0, -1}, {1, 0}, {-1, 0} };
    char maps[110][110];
    void Init()
    {
        memset(head, -1, sizeof(head));
        memset(maps, 0, sizeof(maps));
        edge_num = 0;
    }
    void Add(int x, int y, int flow)
    {
        edge[edge_num].flow = flow;
        edge[edge_num].next = head[x];
        edge[edge_num].v = y;
        head[x] = edge_num++;
    
        edge[edge_num].flow = 0;
        edge[edge_num].v = x;
        edge[edge_num].next = head[y];
        head[y] = edge_num++;
    }
    bool bfs(int start, int over)
    {
        queue<int>Q;
        Q.push(start);
        memset(vis, 0, sizeof(vis));
        vis[start] = 1;
        while(!Q.empty())
        {
            int now = Q.front();
            Q.pop();
            if(now == over)
                return true;
            for(int i=head[now]; i!=-1; i=edge[i].next)
            {
                int v = edge[i].v;
                if(!vis[v] && edge[i].flow>0)
                {
                    vis[v] = vis[now]+1;
                    Q.push(v);
                }
            }
        }
        return false;
    }
    int dfs(int u, int over, int Maxflow)
    {
        if(u == over)
            return Maxflow;
        int now_flow = 0;
    
        for(int i=head[u]; i!=-1; i=edge[i].next)
        {
            int v = edge[i].v;
            if(vis[v] == vis[u]+1 && edge[i].flow>0 && Maxflow-now_flow>0)
            {
                int flow = min(Maxflow-now_flow, edge[i].flow);
    
                flow = dfs(v, over, flow);
    
                edge[i].flow -= flow;
                edge[i^1].flow += flow;
    
                now_flow += flow;
            }
        }
        if(!now_flow)
            vis[u] = -1;
        return now_flow;
    }
    int dinic(int start, int over)
    {
        int ans = 0;
        while(bfs(start, over))
            ans += dfs(start, over, oo);
        return ans;
    }
    int main()
    {
        int T, n, m, icase = 1;
        scanf("%d", &T);
        while(T--)
        {
            Init();
            scanf("%d %d", &n, &m);
            for(int i=1; i<=n; i++)
                scanf("%s", maps[i]+1);
    
            int s = (n+2)*(m+2)+1, e = s + 1;
            for(int i=0; i<=n+1; i++)
                maps[i][0] = maps[i][m+1] = 'D';
    
            for(int i=0; i<=m+1; i++)
                maps[0][i] = maps[n+1][i] = 'D';
    
            int cnt = 0;
            for(int i=0; i<=n+1; i++)
                for(int j=0; j<=m+1; j++)
                    id[i][j] = cnt++;
            cnt = 0;
            for(int i=0; i<=n+1; i++)
                for(int j=0; j<=m+1; j++)
                {
                    for(int k=0; k<4; k++)
                    {
                        int dx = i+dir[k][0];
                        int dy = j+dir[k][1];
                        if(dx>=0 && dx<=n+1 && dy>=0 && dy<=m+1)
                        {
                            cnt++;
                            Add(id[i][j], id[dx][dy], 1);
                        }
                    }
                    if(maps[i][j] == 'E')
                        continue;
                    if(((i+j)%2==1 && maps[i][j]=='.') || ((i+j)%2==0 && maps[i][j]=='D'))
                        Add(s, id[i][j], oo);
                    else
                        Add(id[i][j], e, oo);
                }
            printf("Case %d: %d
    ", icase++, cnt/2-dinic(s, e));
        }
        return 0;
    }
    View Code
  • 相关阅读:
    物联网相关期刊会议
    Java O O第十一天
    mac下安装伪分布hadoop2.6.0和hbase1.0.1.1
    Ubuntu下使用openssl为apache2配置ssl
    ubuntu下安装hadoop
    ubuntu 添加应用到Dash启动器
    Ubuntu12.04中安装Oracle JDK和NetBeans的方法
    Ubuntu12.04中在桌面建立指向网页的链接文件的方法
    Ubuntu12.04中Gvim无法固定到启动器的解决办法
    Ubuntu中apt-get安装或更新软件错误的解决办法
  • 原文地址:https://www.cnblogs.com/zznulw/p/6646872.html
Copyright © 2011-2022 走看看