Uva 1511 Soju

题目大意:已知两个点集,从每个点集中各选出一个点,使得该两点之间的曼哈顿距离最小。

题目链接:http://uva.onlinejudge.org/external/15/1511.pdf

解题思路:我们设第1个点集的x坐标小于0,第二个点集的坐标大于0

由于曼哈顿距离的定义为

abs(x1-x2)+abs(y1-y2)=x2-x1+abs(y1-y2)

将y按照升序排序(两个集合一起排序) 枚举每一个点 同时更新x2-y2(第二个集合)的最小值tmp

由于已经排序 显然 对于每一个目前枚举的点(x1,y1)∈集合1,y1>=y2 

所以距离变成x2-x1+y1-y2=x2-y2+y1-x1=min(tmp+y1-x1)

将数组翻转重新做一遍 这样就是选择集合1中的点的纵坐标<集合2中的点的纵坐标 的情况

过程中不断更新ans即可

这个题目貌似坏掉了 也没有办法提交

#include 
#include 
#include 
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 200005;

int t, n, m, a1, a2, a3, a4;

struct Point {
  int x, y, flag;
} p[N];

bool cmp(Point a, Point b) {
  return a.y < b.y;
}

int solve() {
  int ans = INF;
  sort(p, p + n + m, cmp);
  int tmp = INF;
  for (int i = 0; i < n + m; i++) {
  if (p[i].flag)
    tmp = min(tmp, p[i].x - p[i].y);
  else
    ans = min(ans, p[i].y - p[i].x + tmp);
  }
  tmp = INF;
  reverse(p, p + n + m);
  for (int i = 0; i < n + m; i++) {
  if (p[i].flag)
    tmp = min(tmp, p[i].x + p[i].y);
  else
    ans = min(ans, -p[i].x - p[i].y + tmp);
  }
  return ans;
}

int main() {
  scanf("%d", &t);
  while (t--) {
  scanf("%d", &n);
  for (int i = 0; i < n; i++) {
    scanf("%d%d", &p[i].x, &p[i].y);
    p[i].flag = 0;
  }
  scanf("%d", &m);
  for (int i = n; i < n + m; i++) {
    scanf("%d%d", &p[i].x, &p[i].y);
    p[i].flag = 1;
  }
  printf("%d\n", solve());
  }
  return 0;
}


你可能感兴趣的:(贪心)