牛客网-2018校招真题-堆棋子

题目:
题目描述
小易将n个棋子摆放在一张无限大的棋盘上。第i个棋子放在第x[i]行y[i]列。同一个格子允许放置多个棋子。每一次操作小易可以把一个棋子拿起并将其移动到原格子的上、下、左、右的任意一个格子中。小易想知道要让棋盘上出现有一个格子中至少有i(1 ≤ i ≤ n)个棋子所需要的最少操作次数.
输入描述:
输入包括三行,第一行一个整数n(1 ≤ n ≤ 50),表示棋子的个数
第二行为n个棋子的横坐标x[i](1 ≤ x[i] ≤ 10^9)
第三行为n个棋子的纵坐标y[i](1 ≤ y[i] ≤ 10^9)
输出描述:
输出n个整数,第i个表示棋盘上有一个格子至少有i个棋子所需要的操作数,以空格分割。行末无空格

如样例所示:
对于1个棋子: 不需要操作
对于2个棋子: 将前两个棋子放在(1, 1)中
对于3个棋子: 将前三个棋子放在(2, 1)中
对于4个棋子: 将所有棋子都放在(3, 1)中

思路: 暴力解法。
不过首先要明白:
本题的关键是找到一个最优的聚合点,使得各个棋子到这个聚合点的距离最短。由于x和y轴是相互独立的,互不影响,因此可以先分析x轴再分析y轴。以【1,2,4,9】为例,根据@蟹粉馅大糖包的证明,最优聚合点的x坐标一定是【1,2,4,9】这几个数之一,同理y坐标一定是【1,1,1,1】这几个数之一。有了这个结论,就可以使用暴力法,一一枚举每一个可能的点并计算距离,求出距离最小的那个点。

#include
#include
#include
#define INT_MAX pow(2,31)-1
using namespace std;

int main()
{
	int n;
	cin >> n;
	vector x(n);
	vector y(n);
	for (int i = 0; i < n; ++i)
		cin >> x[i];
	for (int i = 0; i < n; ++i)
		cin >> y[i];
	vector ans(n, INT_MAX);
	for (int i = 0; i < n; ++i)
	{
		for (int j = 0; j < n; ++j)
		{
			vector dis(n);
			for (int k = 0; k < n; ++k)
			{
				dis[k] = abs(x[i] - x[k]) + abs(y[j] - y[k]);
			}
			sort(dis.begin(), dis.end());
			int t = 0;
			for (int k = 0; k < n; ++k)
			{
				t += dis[k];
				ans[k] = min(ans[k], t);
			}
		}
	}
	for (int i = 0; i < n; ++i)
	{
		cout << ans[i];
		if (i != n - 1) cout << " ";
	}
	return 0;
}

你可能感兴趣的:(牛客网-2018校招真题-堆棋子)