• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
LyonLys
愿意在角落唱沙哑的歌 再大声也都是给你 请用心听 不要说话 Contact me via E-mail: lyon.lys@gmail.com
博客园    首页    新随笔    联系   管理    订阅  订阅

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

posted @ 2012-08-13 17:22  LyonLys  阅读(271)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3