HDU-2389(Rain on your Parade )HK算法 + 邻接表优化

题目链接: HDU-2389
此题对时间要求比较高,一共有客人数 <= 3000, 雨伞数 <= 3000. 若用普通的匈牙利算法,即使加上邻接表优化时间复杂度也过高, 所以要使用更优的算法 HK算法Hopcroft-Carp算法求二分图最大匹配数, 时间复杂度为O(sqrt(v)*E), 然后再加上邻接表优化。

匈牙利算法+邻接表优化(TLE)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <cmath>
using namespace std;

const int MAXN = 3005;
struct _Node{
    int x, y, s;
    _Node(int _x, int _y, int _s = -1){
        x = _x;
        y = _y;
        s = _s;
    }
    _Node(){
        s = -1;
    }
};
vector<int> g[MAXN];
int use[MAXN], visit[MAXN];
int t, nx, ny;
_Node pp[MAXN], up[MAXN]; //people position, umbrella position

bool canGet(_Node p, _Node u){
   return sqrt((p.x - u.x)*(p.x - u.x) + (p.y - u.y)*(p.y - u.y)) <= p.s*t; 
}

bool dfs(int x){
    for(int i = 0; i < g[x].size(); ++i){
        int y = g[x][i];
        if(!visit[y]){
            visit[y] = 1;
            if(use[y] == -1 || dfs(use[y])){
                use[y] = x;
                return 1;
            }
        }
    }
    return 0;
}

int getMax(){
    int sum = 0;
    memset(use, -1, sizeof(use));

    for(int x = 1; x <= nx; ++x){
        memset(visit, 0, sizeof(visit));
        if(dfs(x)) sum ++;
    }
    return sum;
}

int main(){
    int T, cnt = 0;
    scanf("%d", &T);
    while(T--){
        for(int i = 0; i < MAXN; ++i) g[i].clear();
        scanf("%d", &t);
        scanf("%d", &nx);
        for(int i = 1; i <= nx; ++i) scanf("%d%d%d", &pp[i].x, &pp[i].y, &pp[i].s);
        scanf("%d", &ny);
        for(int i = 1; i <= ny; ++i) scanf("%d%d", &up[i].x, &up[i].y);
        for(int x = 1; x <= nx; ++x)
            for(int y = 1; y <= ny; ++y) if(canGet(pp[x], up[y])) g[x].push_back(y);
        printf("Scenario #%d:\n%d\n\n", ++cnt, getMax());
    }
    return 0;
}

邻接矩阵HK算法(TLE)

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;

/*
    hk o(sqrt(v)*e) 算法求二分图最大匹配, 时间复杂度比匈牙利算法o(ve)优秀
*/

const int inf = 0x3f3f3f3f;
const int maxn = 3005;
struct _node{
    int x, y, s;
};
int g[maxn][maxn], mx[maxn], my[maxn], visit[maxn];
_node pp[maxn], up[maxn];
int dx[maxn], dy[maxn], dist;
int nx, ny, t;

bool isconnected(_node p, _node u){
    return sqrt((p.x - u.x)*(p.x - u.x) + (p.y - u.y)*(p.y - u.y)) <= p.s*t;
}

//找到最短的增广路
bool bfs(){
    queue<int> q;
    dist = inf;
    memset(dx, -1, sizeof(dx));
    memset(dy, -1, sizeof(dy));

    for(int i = 1; i <= nx; ++i) if(mx[i] == -1){
        q.push(i);
        dx[i] = 0;
    }

    while(!q.empty()){
        int u = q.front();q.pop();
        if(dx[u] > dist) break;
        for(int v = 1; v <= ny; v++){
            if(g[u][v] && dy[v] == -1){
                dy[v] = dx[u] + 1;
                if(my[v] == -1) dist = dy[v];
                else{
                    dx[my[v]] = dy[v] + 1;
                    q.push(my[v]);
                }
            }
        }
    }
    return dist != inf;
}

bool dfs(int u){
    for(int v = 1; v <= ny; ++v){
        if(!visit[v] && g[u][v] && dy[v] == dx[u] + 1){
            visit[v] = 1;
            if(my[v] != -1 && dy[v] == dist) continue;

            if(my[v] == -1 || dfs(my[v])){
                my[v] = u;
                my[u] = v;
                return 1;
            }
        }
    }
    return 0;
}

int maxmatch(){
    int sum = 0;
    memset(mx, -1, sizeof(mx));
    memset(my, -1, sizeof(my));

    while(bfs()){
        memset(visit, 0, sizeof(visit));
        for(int i = 1; i <= nx; ++i){
            if(mx[i] == -1 && dfs(i)) sum++;
        }
    }
    return sum;
}

int main(){

    int T, cnt = 0;
    scanf("%d", &T);
    while(T--){
        memset(g, 0, sizeof(g));
        scanf("%d", &t);
        scanf("%d", &nx);
        for(int i = 1; i <= nx; ++i) scanf("%d%d%d", &pp[i].x, &pp[i].y, &pp[i].s);
        scanf("%d", &ny);
        for(int i = 1; i <= ny; ++i){
            scanf("%d%d", &up[i].x, &up[i].y);
            for(int j = 1; j <= nx; ++j){
                if(isconnected(pp[j], up[i])) g[j][i] = 1;
            }
        }
        printf("scenario #%d:\n%d\n\n", ++cnt, maxmatch());
    }
    return 0;
}

邻接表HK算法(AC)

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <vector>

using namespace std;

const int INF = 0x3f3f3f3f;
const int MAXN = 3005;
struct _node{
    int x, y, s;
};
vector<int> g[MAXN];
int mx[MAXN], my[MAXN];
int dx[MAXN], dy[MAXN];
int dist, t;
bool visit[MAXN];
_node pp[MAXN], up[MAXN];
int un;

bool bfs(){
    queue<int> q;
    dist = INF;
    memset(dx, -1, sizeof(dx));
    memset(dy, -1, sizeof(dy));

    for(int i = 1; i <= un; ++i) if(mx[i] == -1){
        q.push(i);
        dx[i] = 1;
    }

    while(!q.empty()){
        int u = q.front();
        q.pop();
        if(dx[u] > dist) break;
        int size = g[u].size();

        for(int i = 0; i < size; ++i){
            int v = g[u][i];
            if(dy[v] == -1){
                dy[v] = dx[u] + 1;
                if(my[v] == -1) dist = dy[v];
                else{ 
                    dx[my[v]] = dy[v] + 1;
                    q.push(my[v]);
                }
            } 
        }
    }
    return dist != INF;
}

bool dfs(int u){
    for(int i = 0; i < g[u].size(); ++i){
        int v = g[u][i];
        if(!visit[v] && dy[v] == dx[u] + 1){
            visit[v] = 1;
            if(my[v] != -1 && dy[v] == dist) continue;
            if(my[v] == -1 || dfs(my[v])){
                my[v] = u;
                mx[u] = v;
                return 1;
            }
        }
    }
    return 0;
}


int MaxMatch(){
    int sum = 0;
    memset(mx, -1, sizeof(mx));
    memset(my, -1, sizeof(my));
    while(bfs()){
        memset(visit, 0, sizeof(visit));

        for(int u = 1; u <= un; ++u){
            if(mx[u] == -1 && dfs(u)) sum++;
        }
    }
    return sum;
}

bool isconnected(_node p, _node u){
   return (p.x - u.x)*(p.x - u.x) + (p.y - u.y)*(p.y - u.y) <=  p.s*p.s*t*t; 
}
int main(){

    int T, cnt = 0, nx, ny;
    scanf("%d", &T);
    while(T--){
        for(int i = 0; i < MAXN; ++i) g[i].clear();
        scanf("%d", &t);
        scanf("%d", &nx);
        un = nx;
        for(int i = 1; i <= nx; ++i) scanf("%d%d%d", &pp[i].x, &pp[i].y, &pp[i].s);
        scanf("%d", &ny);
        for(int i = 1; i <= ny; ++i) scanf("%d%d", &up[i].x, &up[i].y);
        for(int x = 1; x <= nx; ++x)
            for(int y = 1; y <= ny; ++y) if(isconnected(pp[x], up[y])) g[x].push_back(y);
        printf("Scenario #%d:\n%d\n\n", ++cnt,  MaxMatch());
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值