HDU2389 Rain on your Parade 二分匹配 Hopcroft-Carp的算法+模版

这题目过的挺少的,看着吓人,这道题目一开始用最常用的匈牙利算法就超时,后来网上查了一下,原来给忘了二分匹配中还有一个Hopcroft-Carp的算法,直接找了个模版套了一下,1A,好开心


先讲一下题目的意思,第一行案例数,每个案例第一行 代表还有多少单位时间开始下雨,然后是 N个访客,接下来N行是 每个访客的位置(一维坐标平面内)和他的移动速度,接下来M行 代表雨伞数目,接下来M行表示各个雨伞的位置,问在下雨前 最多有多少人能够拿到雨伞(两个人不共用一把伞)


先给个模版把 模版不是我的 来自kuangbin大神     http://www.cnblogs.com/kuangbin/archive/2011/08/12/2135898.html


/**********************************************
二分图匹配(Hopcroft-Carp的算法)。
初始化:g[][]邻接矩阵
调用:res=MaxMatch();  Nx,Ny要初始化!!!
时间复杂大为 O(V^0.5 E)


适用于数据较大的二分匹配 
***********************************************/ 
const int MAXN=3001;
const int INF=1<<28;
int g[MAXN][MAXN],Mx[MAXN],My[MAXN],Nx,Ny;
int dx[MAXN],dy[MAXN],dis;
bool vst[MAXN];
bool searchP()
{
    queue<int>Q;
    dis=INF;
    memset(dx,-1,sizeof(dx));
    memset(dy,-1,sizeof(dy));
    for(int i=0;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]>dis)  break;
        for(int v=0;v<Ny;v++)
            if(g[u][v]&&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 v=0;v<Ny;v++)
       if(!vst[v]&&g[u][v]&&dy[v]==dx[u]+1)
       {
           vst[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 MaxMatch()
{
    int res=0;
    memset(Mx,-1,sizeof(Mx));
    memset(My,-1,sizeof(My));
    while(searchP())
    {
        memset(vst,0,sizeof(vst));
        for(int i=0;i<Nx;i++)
          if(Mx[i]==-1&&DFS(i))  res++;
    }
    return res;   
}

接下来是本题的代码,基本就是套模版,而且很多地方 用过匈牙利算法的一看就懂了,刚好过1000ms的代码,题目要求是3000ms,不过貌似有人在1000内的 好厉害


#include<iostream>
#include<cstdio>
#include<list>
#include<algorithm>
#include<cstring>
#include<string>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<cmath>
#include<memory.h>
#include<set>

#define ll long long
#define LL __int64
#define eps 1e-8
const ll INF=9999999999999;

using namespace std;

#define M 400000100

#define inf 0xfffffff

//vector<pair<int,int> > G;
//typedef pair<int,int> P;
//vector<pair<int,int>> ::iterator iter;
//
//map<ll,int>mp;
//map<ll,int>::iterator p;

vector<int>G[8000];

int mp[5012][5012];
int num[5012];
int lmarry[5012],rmarry[5012];
bool vis[5012];
int v[5012];
int dx[5012],dy[5012];

int dis[2][4]={0,-1,0,1,1,0,-1,0};

int n,m,k;

struct Node
{
	int x,y;
}l[5012],r[5012];

void clear()
{
	memset(lmarry,-1,sizeof(lmarry));
	memset(rmarry,-1,sizeof(rmarry));
	memset(vis,false,sizeof(vis));
	memset(mp,0,sizeof(mp));
	for(int i=0;i<=m;i++)
		G[i].clear();
}

double distance(int i,int j)
{
	return sqrt(double((l[i].x-r[j].x)*(l[i].x-r[j].x)+(l[i].y-r[j].y)*(l[i].y-r[j].y)));
}

bool detal()
{
	queue<int>q;
	memset(dx,0,sizeof(dx));
	memset(dy,0,sizeof(dy));
	int u,v;
	bool flag=false;
	for(int i=1;i<=m;i++)
		if(lmarry[i]==-1)
			q.push(i);
	while(!q.empty())
	{
		u=q.front();
		q.pop();
		for(int i=0;i<G[u].size();i++)
		{
			v=G[u][i];
			if(!dy[v])
			{
				dy[v]=dx[u]+1;
				if(rmarry[v]==-1)
					flag=true;
				else
				{
					dx[rmarry[v]]=dy[v]+1;
					q.push(rmarry[v]);
				}
			}
		}
	}
	return flag;
}

bool dfs(int x)
{
	for(int i=0;i<G[x].size();i++)
	{
		int v=G[x][i];
		if(dy[v]==dx[x]+1 && !vis[v])
		{
			vis[v]=true;
			if(rmarry[v]==-1 || dfs(rmarry[v]))
			{
				rmarry[v]=x;
				lmarry[x]=v;
				return 1;
			}
		}
	}
	return 0;
}

int main(void)
{
	int Case=0;
	int t;
	cin>>t;
	while(t--)
	{
		printf("Scenario #%d:\n",++Case);
		scanf("%d",&n);
		scanf("%d",&m);
		clear();
		for(int i=1;i<=m;i++)
			scanf("%d %d %d",&l[i].x,&l[i].y,&v[i]);
		scanf("%d",&k);
		for(int i=1;i<=k;i++)
			scanf("%d %d",&r[i].x,&r[i].y);
		for(int i=1;i<=m;i++)
		{
			for(int j=1;j<=k;j++)
				if(v[i]*n>=distance(i,j))
					G[i].push_back(j);
		}
		int ans=0;
		while(detal())
		{
			memset(vis,false,sizeof(vis));
			for(int i=1;i<=m;i++)
				if(lmarry[i]==-1)
				{
					if(dfs(i))
						ans++;
				}
		}
		printf("%d\n\n",ans);
	}
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值