zoukankan      html  css  js  c++  java
  • [bzoj1001][BJOI2006]狼抓兔子——最大流转最短路,平面图

    题目描述:

    给定一个平面图,求最小割。

    题解:

    本题是一道经典题.
    周冬Orz的论文是很好的研究资料。
    这道题点太多,所以直接跑dinic无疑会超时。
    我们观察原图,发现原图是一个平面图。
    什么是平面图呢?平面图就是可以画在平面上,边没有交错的图。
    平面图有几个很吼的性质:

    1. 欧拉定理(欧拉的定理真多。。):如果平面图把平面分为f个面,有n个点,m条边,那么我们有:

    [f = m - n + 2 ]

    1. 任何一个平面图的对偶图还是一个平面图。

    这里的对偶图指的是把原图中的面当作点,边还是边进行构图得到的图。
    我们很容易发现,对偶图中的一个环就是原图的一个最小割。
    但是,显然我们求环还是比较麻烦的。
    我们考察原图性质,
    如果在st中间连一条新边,显然新图还是平面图,同时会比原图多出一个面,我们称之为副面,
    对于这个新图,我们构对偶图,同时令副面和最大的面一个为起点,一个为终点,显然对偶图中的最短路就是原图的一个最小割。
    然后spfa解决就好辣。
    本题最恶心的点在于建对偶图。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = (1000 * 1000 + 50) * 2;
    int n, m, nm, s, t;
    int dist[maxn];
    struct edge {
      int to, weigh;
    };
    vector<edge> G[maxn];
    void add_edge(int from, int to, int weigh) {
      G[from].push_back((edge){to, weigh});
      G[to].push_back((edge){from, weigh});
    }
    void spfa() {
      queue<int> q;
      memset(dist, 127, sizeof(dist));
      dist[s] = 0;
      q.push(s);
      int inq[maxn];
      memset(inq, 0, sizeof(inq));
      inq[s] = 1;
      while (!q.empty()) {
        int u = q.front();
        q.pop();
        inq[u] = 0;
        for (int i = 0; i < G[u].size(); i++) {
          edge &e = G[u][i];
          if (dist[e.to] > dist[u] + e.weigh) {
            dist[e.to] = dist[u] + e.weigh;
            if (inq[e.to] == 0) {
              q.push(e.to);
              inq[e.to] = 1;
            }
          }
        }
      }
    }
    int main() {
      scanf("%d%d", &n, &m);
      nm = (n * m - m - n + 1) << 1;
      s = 0, t = nm + 1;
      //横向边
      int x;
      for (int j = 1; j < m; j++) {
        scanf("%d", &x);
        add_edge(j, t, x);
      }
      for (int i = 1; i < (n - 1); i++) {
        for (int j = 1; j < m; j++) {
          scanf("%d", &x);
          add_edge((i << 1) * (m - 1) + j, ((i << 1) - 1) * (m - 1) + j, x);
        }
      }
      for (int j = 1; j < m; j++) {
        scanf("%d", &x);
        add_edge(((n << 1) - 3) * (m - 1) + j, 0, x);
      }
      //纵向边
      for (int i = 0; i < n - 1; i++) {
        for (int j = 1; j <= m; j++) {
          scanf("%d", &x);
          if (j == 1)
            add_edge(0, (i << 1) * (m - 1) + m, x);
          else if (j == m)
            add_edge((i << 1 | 1) * (m - 1), t, x);
          else
            add_edge((i << 1) * (m - 1) + j - 1, (i << 1) * (m - 1) + j + m - 1, x);
        }
      }
      //斜
      for (int i = 0; i < n - 1; i++) {
        for (int j = 1; j < m; j++) {
          scanf("%d", &x);
          add_edge((i << 1 | 1) * (m - 1) + j, (i << 1) * (m - 1) + j, x);
        }
      }
      spfa();
      printf("%d", dist[t]);
    }
    
  • 相关阅读:
    金蝶KIS 13.0专业版破解方法破解安装流程 金蝶KIS 13.0专业版安装流程
    android利用zbar二维码扫描-(解决中文乱码及扫描区域定义)
    Android 电子邮件发送成功与失败的提示
    WebView的应用 持续积累
    [LeetCode]Implement Stack using Queues
    android开发 Fragment嵌套调用常见错误
    【剑指Offer学习】【面试题55:字符流中第一个不反复的字符】
    UIWebView的使用,简单浏览器的实现
    php 发送与接收流文件
    IHttpModule在webconfig中的注册
  • 原文地址:https://www.cnblogs.com/gengchen/p/6403138.html
Copyright © 2011-2022 走看看