NOI 4.3 1538: Gopher II(匈牙利算法求最大匹配)

题目来源:http://noi.openjudge.cn/ch0403/1538/

1538: Gopher II

总时间限制2000ms   内存限制65536kB

描述

The gopher family, having averted the canine threat, must face anew predator. 

The are n gophers and m gopher holes, each at distinct (x, y) coordinates. Ahawk arrives and if a gopher does not reach a hole in s seconds it isvulnerable to being eaten. A hole can save at most one gopher. All the gophersrun at the same velocity v. The gopher family needs an escape strategy thatminimizes the number of vulnerable gophers.

输入

The input contains several cases. The first line of each casecontains four positive integers less than 100: n, m, s, and v. The next n linesgive the coordinates of the gophers; the following m lines give the coordinatesof the gopher holes. All distances are in metres; all times are in seconds; allvelocities are in metres per second.

输出

Output consists of a single line for each case, giving thenumber of vulnerable gophers.

样例输入

2 2 5 10
1.0 1.0
2.0 2.0
100.0 100.0
20.0 20.0

样例输出

1

来源

Waterloo local 2001.01.27

 -----------------------------------------------------

思路

把老鼠看做二分图的左半部,把地洞看做二分图的右半部,如果老鼠能跑进地洞就在老鼠和地洞之间连一条边,问题转化为求二分图的最大匹配。由于需要频繁查找一个节点的相邻节点,故用邻接表存储二分图。

用匈牙利算法求解,其中搜索增广道路用递归深搜实现。数组link表示节点的匹配关系,一个算例只有一个link数组;数组vis表示一次增广道路的求解过程中节点是否被访问,每次增广道路的求解过程vis都不同,需要每次清零

-----------------------------------------------------

代码

#include<iostream>
#include<fstream>
#include<vector>
#include<cstring>
using namespace std;

const int GMAX = 105;					// max(n)
const int NMAX = 205;					// max(m+n)
int n,m;
int link[NMAX] = {};					// 一个节点的匹配节点(n+m)个
bool vis[NMAX] = {};					// 该节点是否被访问过
vector<int> G[NMAX] = {};				// 邻接表
double g_x[GMAX] = {};					// n只老鼠的坐标
double g_y[GMAX] = {};
double h_x[GMAX] = {};					// m个地洞的坐标
double h_y[GMAX] = {};

int dfs(int i)							// 求从i开始的增广道路(递归),存在则返回1,不存在返回0
{
	vector<int> v = G[i];
	vector<int>::iterator it;
	int j;
	for (it=v.begin(); it!=v.end(); it++)			// 遍历i的相邻节点
	{
		j = *it;
		if (!vis[j])								// 如果j未标记
		{
			vis[j] = 1;								// 把j标记为已访问
			if (link[j]==-1 || dfs(link[j]))		// 如果j还没有匹配或存在从j出发的增广道路
			{
				link[j] = i;						// 更改j的后继节点为i
				return 1;							// 找到一条增广道路
			}
		}
	}
	return 0;										// 找不到增广道路
}


int main()
{
#ifndef ONLINE_JUDGE
	ifstream fin ("0403_1538.txt");
	int i,j;
	double s,v,rad,ans;
	while (fin >> n >> m)
	{
		fin >> s >> v;
		rad = s*v;
		memset(link, -1, sizeof(link));
		memset(vis, 0, sizeof(vis));
		for (i=0; i<NMAX; i++)
		{
			G[i].clear();
		}
		for (i=0; i<n; i++)
		{
			fin >> g_x[i] >> g_y[i];
		}
		for (i=0; i<m; i++)
		{
			fin >> h_x[i] >> h_y[i];
			for (j=0; j<n; j++)					// 求邻接表
			{
				if ((h_x[i]-g_x[j])*(h_x[i]-g_x[j])+(h_y[i]-g_y[j])*(h_y[i]-g_y[j])<=rad*rad)
				{
					G[n+i].push_back(j);
					G[j].push_back(n+i);
				}
			}
		}
		ans = 0;
		for (i=0; i<n; i++)
		{
			memset(vis, 0, sizeof(vis));		// 每次找增广道路之前把vis数组清零
			ans += dfs(i);						// 从i出发是否存在增广道路
		}
		cout << (n-ans) << endl;
	}
	fin.close();
#endif
#ifdef ONLINE_JUDGE
	int i,j;
	double s,v,rad,ans;
	while (cin >> n >> m)
	{
		cin >> s >> v;
		rad = s*v;
		memset(link, -1, sizeof(link));
		memset(vis, 0, sizeof(vis));
		for (i=0; i<NMAX; i++)
		{
			G[i].clear();
		}
		for (i=0; i<n; i++)
		{
			cin >> g_x[i] >> g_y[i];
		}
		for (i=0; i<m; i++)
		{
			cin >> h_x[i] >> h_y[i];
			for (j=0; j<n; j++)					// 求邻接表
			{
				if ((h_x[i]-g_x[j])*(h_x[i]-g_x[j])+(h_y[i]-g_y[j])*(h_y[i]-g_y[j])<=rad*rad)
				{
					G[n+i].push_back(j);
					G[j].push_back(n+i);
				}
			}
		}
		ans = 0;
		for (i=0; i<n; i++)
		{
			memset(vis, 0, sizeof(vis));		// 每次找增广道路之前把vis数组清零
			ans += dfs(i);						// 从i出发是否存在增广道路
		}
		cout << (n-ans) << endl;
	}
#endif
}


猜你喜欢

转载自blog.csdn.net/da_kao_la/article/details/80747989
4.3