luogu1632 点的移动

其实只需要开三重循环

根据OI中的一个重要的原理

给定一个序列a,求一个数x使得\(\sum |a_i-x|\)最小,那么这个数是序列a的中位数

证明略

然后既然是中位数,一定是数列中的数,类比到这题,聚集到的点的横纵坐标一定都存在于某些点上,所以O(n^2)枚举聚集到哪个点。
然后求出所有点到这个聚集点的距离,sort一下,求一个前缀和,更新ans数组即可,预计复杂度\(O(n^3\log n)\)

#include <bits/stdc++.h>
using namespace std;

struct coord
{
	int x, y;
} a[55];

int n, ans[55], dis[55];

int main()
{
	scanf("%d", &n);
	memset(ans, 0x3f, sizeof(ans));
	for (int i = 1; i <= n; i++)
		scanf("%d%d", &a[i].x, &a[i].y);
	for (int x = 1; x <= n; x++)
		for (int y = 1; y <= n; y++)
		{
			for (int p = 1; p <= n; p++)
				dis[p] = abs(a[p].x - a[x].x) + abs(a[p].y - a[y].y);
			sort(dis + 1, dis + 1 + n, less<int>());
			for (int p = 1; p <= n; p++)
			{
				dis[p] += dis[p - 1];
				ans[p] = min(ans[p], dis[p]);
			}
		}
	for (int i = 1; i <= n; i++)
		printf("%d\n", ans[i]);
	return 0;
}

posted @ 2018-09-06 09:59  ghj1222  阅读(100)  评论(0编辑  收藏  举报