zoukankan      html  css  js  c++  java
  • hdu 2389 Rain on your Parade

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

      Hopcroft-Karp算法是二分匹配的一个十分快捷的算法,相对于匈牙利算法在时间上有了相当大的改进!

      hdu 2389 这题我是前两天尝试做二分匹配的题的时候遇见的,当时我看到点的规模达到3000个,我就想到这题不能用匈牙利算法来过。不过当时我还不会hk算法,所以我只好当作练习匈牙利算法,打了一遍交上去!回来的结果必然是TLE。然后,我只好看了一下题解,才发现hk算法这神级速度的二分匹配算法!

      我想说一下的是,在图论的算法中,用的最多的优化方式就是将dfs转化成bfs,用队列,优先队列,亦或是单调队列来加快算法的工作速度。

      这题如果是用dfs,那么搜n个点,e条边,最高的复杂度可以达到O(n^3)。其中的原因是搜索n个点可能出现每次都要搜索大量的边,然而,这些被搜索的边很多都是没必要的。于是,在匈牙利算法的基础上,在dfs前用bfs的方法来预留可能匹配的边,然后dfs搜索的时候就可以减少不必要的搜索,从而加快搜索速度!

    代码如下(8.16修改):

    View Code
      1 #include <cstdio>
      2 #include <cstdlib>
      3 #include <cstring>
      4 #include <vector>
      5 
      6 using namespace std;
      7 const int maxn = 3001;
      8 
      9 int dx[maxn], dy[maxn], mx[maxn], my[maxn];
     10 int q[maxn << 1], qh, qt;
     11 vector<int> rel[maxn];
     12 struct point{
     13     int x, y;
     14     int v;
     15 }guest[maxn];
     16 
     17 int bfs(int n, int m){
     18     bool ret = false;
     19 
     20     qh = qt = 0;
     21     for (int i = 1; i <= m; i++){
     22         dy[i] = 0;
     23     }
     24     for (int i = 1; i <= n; i++){
     25         dx[i] = 0;
     26         if (mx[i] == -1){
     27             q[qt++] = i;
     28         }
     29     } // reset status of x&y-set using array dx & dy and queue-in the x-nodes which are not matched
     30 
     31     while (qh != qt){ // set distance of every pair of x,y-nodes
     32         int cur = q[qh++];
     33 
     34         for (int i = 0; i < rel[cur].size(); i++){
     35             int t = rel[cur][i];
     36 
     37             if (!dy[t]){
     38                 dy[t] = dx[cur] + 1;
     39                 if (my[t] == -1){
     40                     ret = true;
     41                 }
     42                 else{
     43                     dx[my[t]] = dy[t] + 1;
     44                     q[qt++] = my[t]; // 前一个版本将my[t]写成t水过去了
     45                 } // if t is matched, let the x-node matched with t queue-in and find its other adjacent y-nodes
     46             }
     47         }
     48     }
     49 
     50     return ret;
     51 }
     52 
     53 bool dfs(int cur){
     54     for (int i = 0; i < rel[cur].size(); i++){
     55         int t = rel[cur][i];
     56 
     57         if (dy[t] == dx[cur] + 1){ // if satisfied the pair distance, go deeper
     58             dy[t] = 0;
     59             if (my[t] == -1 || dfs(my[t])){
     60                 my[t] = cur;
     61                 mx[cur] = t;
     62 
     63                 return true;
     64             } // find a satisfied pair
     65         }
     66     }
     67 
     68     return false;
     69 }
     70 
     71 int hk(int n, int m){
     72     int cnt = 0;
     73 
     74     for (int i = 1; i <= n; i++){
     75         mx[i] = my[i] = -1;
     76     }
     77     while (bfs(n, m)){
     78         for (int i = 1; i <= n; i++){
     79             if (mx[i] == -1 && dfs(i)){
     80                 cnt++;
     81             }
     82         }
     83     }
     84 
     85     return cnt;
     86 }
     87 
     88 bool judge(point g, point u, int t){
     89     int x = g.x - u.x;
     90     int y = g.y - u.y;
     91     int s = g.v * t;
     92 
     93     if (x * x + y * y <= s * s){
     94         return true;
     95     }
     96 
     97     return false;
     98 }
     99 
    100 void deal(int c){
    101     int n, m, t;
    102 
    103     scanf("%d", &t);
    104     scanf("%d", &n);
    105     for (int i = 1; i <= n; i++){
    106         scanf("%d%d%d", &guest[i].x, &guest[i].y, &guest[i].v);
    107         rel[i].clear();
    108     }
    109     scanf("%d", &m);
    110     for (int i = 1; i <= m; i++){
    111         scanf("%d%d", &guest[0].x, &guest[0].y);
    112         for (int j = 1; j <= n; j++){
    113             if (judge(guest[j], guest[0], t)){
    114                 rel[j].push_back(i);
    115             }
    116         }
    117     }
    118 
    119     printf("Scenario #%d:\n%d\n\n", c, hk(n, m));
    120 }
    121 
    122 int main(){
    123     int n;
    124 
    125 #ifndef ONLINE_JUDGE
    126     freopen("in", "r", stdin);
    127 #endif
    128 
    129     scanf("%d", &n);
    130     for (int i = 1; i <= n; i++)
    131         deal(i);
    132 
    133     return 0;
    134 }

      修改内容包括:

    1.删除记录入队情况的bool数组,因为元素不会入队两次

    2.在hk函数中,dfs前必须判断该边是否已经匹配

    hk算法:http://www.cnblogs.com/LyonLys/archive/2012/08/11/Hopcroft_Karp_Lyon.html

     ——written by Lyon

  • 相关阅读:
    如何诊断RAC数据库上的“IPC Send timeout”问题?
    ORA-1157处理过程
    ORA-1157 Troubleshooting
    SQL优化案例(执行计划固定)
    数据库io层面故障
    sql优化案例(索引创建不合理)
    SQL优化案例(union问题)
    Redis在Windows下的安装与使用
    npm使用淘宝镜像
    基于compose单机部署 etcd + coredns
  • 原文地址:https://www.cnblogs.com/LyonLys/p/hdu_2389_Lyon.html
Copyright © 2011-2022 走看看