1. 程式人生 > >【二分圖-HK演算法】HDU

【二分圖-HK演算法】HDU

題意:

二維平面上m個人和n把傘,一把傘只能給一個人。每個人都有自身的速度,問規定時間t內最多有幾個人能拿到傘。

(1 <=t <= 5;1 <= m <= 3000;1 <= n <= 3000)

題解:

典型的二分圖,人和傘作點,能在規定時間到的連一條邊。

但這題的範圍比較大。匈牙利演算法的複雜度是O(VE),肯定會超時。

而Hopcroft-Carp適用於多點的情況,複雜度為O(sqrt(V)E),這樣就能過了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e3+7;
const int M=1e7+7;
const int inf=1<<28;
struct Edge{
    int v,nxt;
    Edge(int v=0,int nxt=0):v(v),nxt(nxt){}
}e[M];
int p[N],edn;
void add(int u,int v){
    e[++edn]=Edge(v,p[u]);p[u]=edn;
}
int mx[N],my[N],dx[N],dy[N],dis,n,m;
bool vis[N];
bool bfs(){
    queue<int>q;
    dis=inf;
    memset(dx,-1,sizeof(dx));
    memset(dy,-1,sizeof(dy));
    for(int i=0;i<n;i++){
        if(mx[i]==-1){
            q.push(i);
            dx[i]=0;
        }
    }
    while(!q.empty()){
        int u=q.front();
        q.pop();
        if(dx[u]>dis)  break;
        for(int i=p[u];~i;i=e[i].nxt){
            int v=e[i].v;
            if(dy[v]==-1){
                dy[v]=dx[u]+1;
                if(my[v]==-1) dis=dy[v];
                else{
                    dx[my[v]]=dy[v]+1;
                    q.push(my[v]);
                }
            }
        }
    }
    return dis!=inf;
}
bool dfs(int u){
    for(int i=p[u];~i;i=e[i].nxt){
        int v=e[i].v;
        if(!vis[v]&&dy[v]==dx[u]+1){
            vis[v]=1;
            if(my[v]!=-1&&dy[v]==dis) continue;
            if(my[v]==-1||dfs(my[v])){
                my[v]=u;
                mx[u]=v;
                return 1;
            }
       }
    }
    return 0;
}
int hk(){
    int res=0;
    memset(mx,-1,sizeof(mx));
    memset(my,-1,sizeof(my));
    while(bfs()){
        memset(vis,0,sizeof(vis));
        for(int i=0;i<n;i++){
            if(mx[i]==-1&&dfs(i)) res++;
        }
    }
    return res;
}
struct Node{
    int x,y,z;
}a[N],b[N];
int main(){
    int t,cs=0,lim;
    scanf("%d",&t);
    while(t--){
        memset(p,-1,sizeof(p));edn=-1;
        scanf("%d",&lim);
        scanf("%d",&n);
        for(int i=0;i<n;i++)
            scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].z);
        scanf("%d",&m);
        for(int i=0;i<m;i++)
            scanf("%d%d",&b[i].x,&b[i].y);
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if((a[i].x-b[j].x)*(a[i].x-b[j].x)+(a[i].y-b[j].y)*(a[i].y-b[j].y)<=lim*a[i].z*lim*a[i].z){
                    add(i,j);
                }
            }
        }
        printf("Scenario #%d:\n%d\n\n",++cs,hk());
    }
}