题意:给一些人和一些伞的坐标,然后每个人都有一定的速度,还有多少时间就会下雨,问最多能有多少人可以拿到伞。
分析:题意很明确,可以用每个人和伞判断一下是否能够达到,如果能就建立一个联系。不过这道题的数据还是挺大的,第一次使用的匈牙利算法果断的TLE了,然后就百度了一下发现有一个 Hopcroft-Karp算法 不过这个算法网上描述的很少,而且都说的比较含糊不清,不过幸好搜到一个比较不错的课件,看了一上午总算有些明白怎么回事,以前是寻找一个增广路,这个是寻找所有的增广路,并且使用BFS进行分层,看起来比较高大上,虽然我还是不明白怎么减少的复杂度(提交确实不不超时了).......后面做题在慢慢理解吧
课件连接 :
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
const int MAXN = 3005;
const int oo = 1e9+7;
struct point{int x, y, v;}p[MAXN], um;
bool OK(point a, point b, int v)
{///判断两点是否在合法范围内,也就是下雨前能否达到
int len = (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y);
if(len > v*v)
return false;
return true;
}
struct Edge{int v, next;}e[MAXN*MAXN];
int Head[MAXN], cnt;
void AddEdge(int u, int v)
{///邻接表,点比较多,不好开邻接矩阵
e[cnt].v = v;
e[cnt].next = Head[u];
Head[u] = cnt++;
}
bool used[MAXN];
int Mx[MAXN], My[MAXN];///记录的所匹配的端点,0表示未匹配
int dx[MAXN], dy[MAXN];///BFS分层时,记录点所在的层,-1表示不在分层
int Nx, Ny, depth;///Nx个人,Ny把雨伞, depth记录分层的深度
bool BFS()///如果发现y这边有增广路,返回1,否则返回0
{
queue<int> Q; depth = oo;
memset(dx, -1, sizeof(dx));
memset(dy, -1, sizeof(dy));
for(int i=1; i<=Nx; i++)
{
if( Mx[i] == false )
{
dx[i] = 0;
Q.push(i);
}
}
while(Q.size())
{
int x = Q.front(); Q.pop();
if(dx[x] > depth) break;///已经找到了增广路,不必寻找下层
for(int j=Head[x]; j!=-1; j=e[j].next)
{
int y = e[j].v;
if( dy[y] == -1 )
{
dy[y] = dx[x] + 1;
if(My[y] == false)
depth = dy[y];
else
{
dx[ My[y] ] = dy[y] + 1;
Q.push( My[y] );
}
}
}
}
if( depth == oo )
return false;
return true;
}
bool Find(int i)
{
for(int j=Head[i]; j!=-1; j=e[j].next)
{
int v = e[j].v;
if( !used[v] && dx[i] == dy[v]-1)
{
used[v] = true;
if( My[v] && dy[v] == depth )
continue;///不会在下一层,因为还没有对下层进行增广
if( !My[v] || Find( My[v] ) )
{
My[v] = i;
Mx[i] = v;
return true;
}
}
}
return false;
}
int Karp()
{
int ans = 0;
memset(Mx, false, sizeof(Mx));
memset(My, false, sizeof(My));
while( BFS() == true )
{///如果还存在增广路
memset(used, false, sizeof(used));
for(int i=1; i<=Nx; i++)
{
if( !Mx[i] && Find(i) == true )
ans++;
}
}
return ans;
}
int main()
{
int T, t=1;
scanf("%d", &T);
while(T--)
{
int i, j, time;
scanf("%d%d", &time, &Nx);
memset(Head, -1, sizeof(Head));
cnt = 0;
for(i=1; i<=Nx; i++)
scanf("%d%d%d", &p[i].x, &p[i].y, &p[i].v);
scanf("%d", &Ny);
for(i=1; i<=Ny; i++)
{
scanf("%d%d", &um.x, &um.y);
for(j=1; j<=Nx; j++)
{
if( OK(p[j], um, p[j].v*time) )
AddEdge(j, i);
}
}
int ans = Karp();
printf("Scenario #%d:\n", t++);
printf("%d\n\n", ans);
}
return 0;
}