Bootstrap

洛谷 P9709 [KMOI R1] 军事行动

题目背景

他们来了。

集结军队,干掉他们,一个不留。

是!

题目描述

喵星边境局势愈发紧张,导致发生边境冲突。喵星军队总司令小袁立即对Y星采取军事行动。

整个宇宙可以看作一个平面直角坐标系,城市1, 2, ..., n的坐标分别为
(x1, y1), (x2, y2), ..., (xn, yn)。

现在小袁率领的若干支舰队(可以理解为小袁的军事力量是无限的)驻扎在边境要塞,城市1处。他的舰队会进行以下移动:

  • 如果舰队的坐标为(x, y),那么一天之后它可以移动到(x - 1, y + 2)或(x + 1, y + 2)或(x + 2, y + 1)或(x - 2, y + 1)或(x - 1, y - 2)或(x + 1, y - 2)或(x + 2, y - 1)或(x - 2, y - 1)处。

其中环境在外的还有一条小行星带,当舰队的坐标(x, y)且x ≤ 0或y ≤ 0或m < x或m < y时,舰队就会撞到小行星带。这是小袁所不想看到的。

现在小袁要攻打城市2, 3, ..., n,每一次他都会从一个已经占领的城市(城市1也算),派出舰队前往城市i并攻打它,舰队到达之后的第二天城市i就被攻占了。

特别的,小袁在一个舰队前往攻打或攻打一个城市的时候不会派出另外一支舰队,在攻占一座城市后当天可以立即派出另外一支舰队。

小袁想问,最少要花多少时间才能攻占所有的城市。

攻打顺序可以不按照2, 3, ... n的顺序。

输入格式

第一行一个整数n, m,表示城市个数和小行星带的范围。

接下来n行,每一行两个正整数(xi, yi),表示城市i的坐标。保证1 ≤ xi, yi ≤ m。

输出格式

一个整数 ans,表示最少花花的时间。

输入输出样例

输入 #1
2 20
1 1
1 3
输出 #1
3
输入 #2
3 150
1 2
2 4
4 3
输出 #2
4
输入 #3
10 10
1 4
2 3
2 6
3 6
10 3
1 5
4 2
5 3
2 8
9 2
输出 #3
23
输入 #4

查看附件的 exampled.in

输出 #4

查看附件的 exampled.out

说明/提示

样例一解释:
部队在第一天来到了 (3,2) 的位置,第二天到达了城市 2 的位置,第三天占领了城市 2。总共花了 3 天。

样例二解释:
部队在第一天到达了城市 2 的位置,第二天占领了城市 2,第三天到达了城市 3 的位置,第四天占领了城市 3。总共花了 4 天。

数据范围

本器采用 Subtask 描述测试。

子任务编号测试点编号nm特殊性质分值
11 ~ 21 ≤ n ≤ 74 ≤ m ≤ 710
23 ~ 71 ≤ n ≤ 2004 ≤ m ≤ 7025
38 ~ 91 ≤ n ≤ 1504 ≤ m ≤ 15015
410 ~ 201 ≤ n ≤ 20004 ≤ m ≤ 15050

特殊性质:
对于每一个 1 ≤ i ≤ n - 1,都有 xi = xi+1。

数据严格保证不会有不同的城市拥有相同的坐标。

附件下载
@ 平事行/example.zip 317B

思路如下:

bfs构图+kruskal算法

代码如下:

#include<iostream>
#include<algorithm>
#include<queue>
#include<cstring>
#include<unordered_map>
using namespace std;
const int N = 4e6+10;
int n,m,tot; 
int x[2010],y[2010];
bool vis[200][200];
int city[200][200];
bool cs[2010][2010]; //a->b是否存在边 
int dx[] = {-1, 1, 2, -2, -1, 1, 2, -2};  // 方向数组
int dy[] = {2, 2, 1, 1, -2, -2, -1, -1};
struct Node{
	int x,y,step;
};
struct Edge{
	int u,v,w;
}e[N];
bool compare(const Edge &a,const Edge &b)
{
	return a.w < b.w;
}
int fa[N];
int find(int i)
{
	if(fa[i] != i)
	{
		fa[i] = find(fa[i]);
	}
	return fa[i];
}
bool check(int u,int v)
{
	int root_u = find(u);
	int root_v = find(v);
	return root_u == root_v;
}
void set(int u,int v)
{
	int root_u = find(u);
	int root_v = find(v);
	if(root_u != root_v)
	{
		fa[root_v] = root_u;
	}
}
int MST()
{
	int sum = 0,cnt = 0;
	sort(e + 1, e + 1 + tot, compare);
	for(int i = 1 ; i <= tot && cnt < n - 1 ; i++)
	{
		int u = e[i].u;
		int v = e[i].v;
		int w = e[i].w;
		if(!check(u,v))
		{
			set(u,v);
			sum += w;
			cnt++;
		}
	}
	return sum;
}
void bfs(int x,int y ,int num)
{
	queue <Node> r;
	r.push({x,y,1});
	vis[x][y] = true;
	while(!r.empty())
	{
		auto k = r.front();
		r.pop();
		int x = k.x;
		int y = k.y;
		int step = k.step;
		for(int i = 0 ; i < 8 ; i++)
		{
			int tx = x + dx[i];
			int ty = y + dy[i];
			if(tx >= 1 && ty >= 1 && tx <= m && ty <= m && !vis[tx][ty])
			{
				vis[tx][ty] = true;
				r.push({tx,ty,step + 1});
				if(city[tx][ty])
				{
					if(!cs[num][city[tx][ty]])
					{
						cs[num][city[tx][ty]] = true;
						e[++tot] = {num,city[tx][ty],step + 1};				
					}					
				}
			}
		}
		
	}
}
int main(void) 
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
	cin >> n >> m;
	for(int i = 1 ; i <= n ; i++)
	{
		cin >> x[i] >> y[i];
		fa[i] = i;
		city[x[i]][y[i]] = i;
	}
	for(int i = 1 ; i <= n ; i++)
	{
		memset(vis,false,sizeof(vis));
		bfs(x[i],y[i],i);
	}
	int ans = MST();

	cout << ans;
    return 0;
}

;