zoukankan      html  css  js  c++  java
  • HDU 4859 海岸线 最小割

    题目链接:

    http://acm.hdu.edu.cn/showproblem.php?pid=4859

    题解:

    这题考察的是最小割。

    我们可以这样想:海岸线的长短变化都是E引起的,我们通过把’E'变成'.'或'D'来使海岸线最大化。

    我们要算海岸线就是算格子‘.'和格子'D'(在原有地图周围四面都要加’D‘)相邻的面数,要使它最大,就是要使'.'与’.';'D'与'D'相邻的面数最小,而面数最小可以用最小割来做。

    现在我们先把格子上的点黑白染色,(i+j)%2==1的为A类,为0的为B类,

    在A类中,所的’.'与源点相连(容量为INF),所有的’D'与汇点相连(容量为INF)。

    在B类中,所有的‘.'与汇点相连(容量为INF),所有的'D'与源点相连(容量为INF)。

    E不与源点,汇点相连。

    所有的点与周围的四个点连一条有向边(容量为1)。

    图建好啦,跑一下最大流,ans=总的面-最大流。

    现在让我们来研究一下这图的一些性质:

    首先,只有’.'到‘.‘,’D'到'D‘的路径能联通源点汇点

    其次,考虑'E'。

    如果与‘E’相连的四个点都是'.'或都是'D‘,那这个’E‘,不可能有流通过,也就是它最终的属性肯定与周围的是相反的!

    其次如果与‘E'相邻的有’.'和‘D'(这里的'.'和’D'要么都属于A类,要么都属于B类),那么就可能会有不同的流通过(这就是在给E定属性了)。

    我们通过最大流算法求出图的最小割,也就是两边相同的面数的最小值。

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<queue>
    using namespace std;
    
    const int maxn = 55;
    const int INF=0x3f3f3f3f;
    
    struct Edge {
        int from, to, cap, flow;
        Edge(int from,int to,int cap,int flow):from(from),to(to),cap(cap),flow(flow){}
    };
    
    struct Dinic {
        int n, m, s, t;
        vector<Edge> edges;
        vector<int> G[maxn*maxn];
        bool vis[maxn*maxn];
        int d[maxn*maxn];
        int cur[maxn*maxn];
    
        void init(int n) {
            this->n = n;
            for (int i = 0; i < n; i++) G[i].clear();
            edges.clear();
        }
    
        void addEdge(int from, int to, int cap) {
            edges.push_back(Edge(from, to, cap, 0));
            edges.push_back(Edge(to, from, 0, 0));
            m = edges.size();
            G[from].push_back(m - 2);
            G[to].push_back(m - 1);
        }
    
        bool BFS() {
            memset(vis, 0, sizeof(vis));
            queue<int> Q;
            Q.push(s);
            d[s] = 0;
            vis[s] = 1;
            while (!Q.empty()) {
                int x = Q.front(); Q.pop();
                for (int i = 0; i < G[x].size(); i++) {
                    Edge& e = edges[G[x][i]];
                    if (!vis[e.to] && e.cap>e.flow) {
                        vis[e.to] = 1;
                        d[e.to] = d[x] + 1;
                        Q.push(e.to);
                    }
                }
            }
            return vis[t];
        }
        int DFS(int x, int a) {
            if (x == t || a == 0) return a;
            int flow = 0, f;
            for (int& i = cur[x]; i < G[x].size(); i++) {
                Edge& e = edges[G[x][i]];
                if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow)))>0) {
                    e.flow += f;
                    edges[G[x][i] ^ 1].flow -= f;
                    flow += f;
                    a -= f;
                    if (a == 0) break;
                }
            }
            return flow;
        }
        int Maxflow(int s, int t) {
            this->s = s; this->t = t;
            int flow = 0;
            while (BFS()) {
                memset(cur, 0, sizeof(cur));
                flow += DFS(s, INF);
            }
            return flow;
        }
    }dinic;
    
    char str[maxn][maxn];
    int mp[maxn][maxn];
    int n, m,tot;
    const int dx[] = { -1,1,0,0 };
    const int dy[] = { 0,0,-1,1 };
    
    void init() {
        tot = 1;
    }
    
    int main() {
        int tc,kase=0;
        scanf("%d", &tc);
        while (tc--) {
            scanf("%d%d", &n,&m);
            init();
            for (int i = 1; i <= n; i++) {
                scanf("%s", str[i]+1);
            }
            n++, m++;
            for (int i = 0; i <= n; i++) str[i][0] = str[i][m] = 'D';
            for (int j = 0; j <= m; j++) str[0][j] = str[n][j] = 'D';
            for (int i = 0; i <= n; i++) {
                for (int j = 0; j <= m; j++) {
                    mp[i][j] = tot++;
                }
            }
            dinic.init(tot+1);
            for (int i = 0; i <= n; i++) {
                for (int j = 0; j <= m; j++) {
                    for (int k = 0; k < 4; k++) {
                        int x = i + dx[k], y = j + dy[k];
                        if (x < 0 || x > n || y < 0 || y > m) continue;
                        dinic.addEdge(mp[i][j], mp[x][y],1);
                    }
                    if ((i + j) % 2) {
                        if (str[i][j] == '.') {
                            dinic.addEdge(mp[i][j], tot, INF);
                        }
                        else if (str[i][j] == 'D') {
                            dinic.addEdge(0, mp[i][j], INF);
                        }
                    }
                    else {
                        if (str[i][j] == '.') {
                            dinic.addEdge(0, mp[i][j], INF);
                        }
                        else if(str[i][j]=='D') {
                            dinic.addEdge(mp[i][j], tot, INF);
                        }
                    }
                }
            }
            int tmp = dinic.Maxflow(0, tot);
            int ans = (n+1)*(m+1)*2-(m+1)-(n+1)-tmp;
            printf("Case %d: %d
    ",++kase, ans);
        }
        return 0;
    }
  • 相关阅读:
    Bottle python
    mongodb python pymongo
    Directory常用
    File类常用
    Path类的常用方法
    winfrom的单例模式
    325工厂模式和面向对象知识点总结(有点乱凑合看)
    音乐播放器自动播放下一首歌记录
    c#分页类(转)
    c# 简历生成器
  • 原文地址:https://www.cnblogs.com/fenice/p/5557942.html
Copyright © 2011-2022 走看看