zoukankan      html  css  js  c++  java
  • HDU 2389 ——Rain on your Parade——————【Hopcroft-Karp求最大匹配、sqrt(n)*e复杂度】

    Rain on your Parade
    Time Limit:3000MS     Memory Limit:165535KB     64bit IO Format:%I64d & %I64u

    Description

    You’re giving a party in the garden of your villa by the sea. The party is a huge success, and everyone is here. It’s a warm, sunny evening, and a soothing wind sends fresh, salty air from the sea. The evening is progressing just as you had imagined. It could be the perfect end of a beautiful day. 
    But nothing ever is perfect. One of your guests works in weather forecasting. He suddenly yells, “I know that breeze! It means its going to rain heavily in just a few minutes!” Your guests all wear their best dresses and really would not like to get wet, hence they stand terrified when hearing the bad news. 
    You have prepared a few umbrellas which can protect a few of your guests. The umbrellas are small, and since your guests are all slightly snobbish, no guest will share an umbrella with other guests. The umbrellas are spread across your (gigantic) garden, just like your guests. To complicate matters even more, some of your guests can’t run as fast as the others. 
    Can you help your guests so that as many as possible find an umbrella before it starts to pour? 

    Given the positions and speeds of all your guests, the positions of the umbrellas, and the time until it starts to rain, find out how many of your guests can at most reach an umbrella. Two guests do not want to share an umbrella, however. 
     

    Input

    The input starts with a line containing a single integer, the number of test cases. 
    Each test case starts with a line containing the time t in minutes until it will start to rain (1 <=t <= 5). The next line contains the number of guests m (1 <= m <= 3000), followed by m lines containing x- and y-coordinates as well as the speed si in units per minute (1 <= s i<= 3000) of the guest as integers, separated by spaces. After the guests, a single line contains n (1 <= n <= 3000), the number of umbrellas, followed by n lines containing the integer coordinates of each umbrella, separated by a space. 
    The absolute value of all coordinates is less than 10000. 
     

    Output

    For each test case, write a line containing “Scenario #i:”, where i is the number of the test case starting at 1. Then, write a single line that contains the number of guests that can at most reach an umbrella before it starts to rain. Terminate every test case with a blank line. 
     

    Sample Input

    2
    1
    2
    1 0 3
    3 0 3
    2
    4 0
    6 0
    1
    2
    1 1 2
    3 3 2
    2
    2 2
    4 4
     

    Sample Output

    Scenario #1: 2
    Scenario #2: 2
     
     
    题目大意:T组测试数据。每组给t表示还有t分钟要下雨,然后给n,表示有n名游客,分别给出x,y,s表示二维坐标及移动速度。接着是m表示有m个避雨亭,给出x,y表示二维坐标,每个游客都不愿意跟其他人共有避雨亭,问t分钟后,最多可以有多少个游客能避雨。
     
    解题思路:最大匹配。游客跟避雨亭分为二部。如果游客可以移动的距离比当前他离某个避雨亭的距离大,说明他可以过去避雨。就连一条边。对于所有游客都枚举一下。建图完成。然而这个题目不是难在建图,而是数据量大,二部图两边的顶点各有3000个。那么可能最大到9*10^6条边,如果用Hungary的v*e的复杂度,那么肯定会超时。所以这里我们用Hopcroft-Karp求最大匹配。
     
    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #include<queue>
    #include<vector>
    #include<algorithm>
    using namespace std;
    const int maxn = 3100;
    const int INF = 0x3f3f3f3f;
    const double eps = 1e-5;
    struct Guest{
        double x,y,s;
    }guests[maxn];
    struct Umbrella{
        double x,y;
    }umbrellas[maxn];
    double distan(Guest a,Umbrella b){
        double dx = a.x - b.x;
        double dy = a.y - b.y;
        return sqrt(dx*dx+dy*dy);
    }
    vector<int>G[maxn];
    int Mx[maxn], My[maxn], dx[maxn], dy[maxn], used[maxn], dis;
    bool SearchP(int _n){   //传参x部的顶点个数,处理出来dx与dy数组
        queue<int>Q;
        memset(dx,-1,sizeof(dx));
        memset(dy,-1,sizeof(dy));
        int dis = INF;
        for(int i = 1; i <= _n; i++){
            if(Mx[i] == -1){    //将x部的未盖点入队
                dx[i] = 0;
                Q.push(i);
            }
        }
        int v;
        while(!Q.empty()){
            int u = Q.front(); Q.pop();
            if(dx[u] > dis) break;  //没有更小的dis
            for(int i = 0; i < G[u].size(); i++){
                v = G[u][i];
                if(dy[v] == -1){        //如果y部的v没有访问过
                    dy[v] = dx[u] + 1;  //更新dy
                    if(My[v] == -1){    //如果y部的v是未盖点,找到了最短增广路长度
                        dis = dy[v];
                    }else{
                        dx[My[v]] = dy[v] + 1;  //更新v的x部匹配点
                        Q.push(My[v]);          //将v的匹配点入队
                    }
                }
            }
        }
        return dis != INF;                      //找到了最短增广路
    }
    int dfs(int u){
        int v;
        for(int i = 0; i < G[u].size(); i++){
            v = G[u][i];
            if(!used[v] && dy[v] == dx[u] + 1){ //v未访问过且距离相差为1
                used[v] = 1;
                if(My[v] != -1 && dy[v] == dis){    //如果v不是未盖点且已经等于最短增广路距原点距离,说明有更短的可以去增广
                    continue;
                }
                if(My[v] == -1 || dfs(My[v])){  //如果v是y部未盖点或者原来跟v匹配的x部节点能另外找到一个匹配
                    Mx[u] = v;                  //匹配u、v
                    My[v] = u;
                    return true;
                }
            }
        }
        return false;
    }
    int MaxMatch(int ln,int rn){    //传参左、右部顶点个数,返回最大匹配个数
        int ret = 0;
        memset(Mx,-1,sizeof(Mx));   //x部初始化未盖点
        memset(My,-1,sizeof(My));   //y部初始化未盖点
        while(SearchP(ln)){
            memset(used,0,sizeof(used));    //初始化未访问
            for(int i = 1; i <= ln; i++){
                if(Mx[i] == -1 && dfs(i)){  //如果x部为未盖点且找到了增广路
                    ret++;
                }
            }
        }
        return ret;
    }
    int main(){
        int T, cas = 0, n, m;
        double t;
        scanf("%d",&T);
        while(T--){
            scanf("%lf",&t);
            scanf("%d",&m);
            for(int i = 0; i <= m; i++){
                G[i].clear();
            }
            for(int i = 1; i <= m; i++){
                scanf("%lf%lf%lf",&guests[i].x,&guests[i].y,&guests[i].s);
            }
            scanf("%d",&n);
            for(int i = 1; i <= n; i++){
                scanf("%lf%lf",&umbrellas[i].x,&umbrellas[i].y);
            }
            for(int i = 1; i <= m; i++){
                for(int j = 1; j <= n; j++){
                    double dd = distan(guests[i],umbrellas[j]);
                    if(guests[i].s * t >= dd){
                        G[i].push_back(j);
                    }
                }
            }
            int res = MaxMatch(m,n);
            printf("Scenario #%d:
    %d
    
    ",++cas,res);
        }
        return 0;
    }
    

      

     
     
  • 相关阅读:
    解决tomcat启东时一闪而过的问题
    如果数据库中的时间类型与mybatis的时间类型对应关系
    el 表达式中某一项过长时需要截取字符串长度,当悬停的时候显示全部内容
    ubuntu/linux系统中安装jdk以及eclipse(附图解详细步骤)
    Unity利用SMSSDK实现短信验证码(附代码)
    Unity利用Share SDK实现QQ、微信及微博第三方登录及定制内容分享(附代码)
    Unity编辑器扩展
    VR中射线点击按钮的实现
    Unity中几个特殊路径在各个平台的访问方式
    多态
  • 原文地址:https://www.cnblogs.com/chengsheng/p/4955426.html
Copyright © 2011-2022 走看看