2017"百度之星"程序设计大赛 - 资格赛

1001.  度度熊保护村庄

这题是要求包含凸包的最小点数的凸包。假设凸包是A型点,外围点是B型点。那么如果对于所有Bi点对于凸包A做右切线,那么如果需要Bi点包围凸包A,显然是切线右边的点才可以和Bi相连。于是这时候是可以n^3暴力的。但是,其实对于Bi点来说,它能连到的最好的点,显然是所有满足的点中,右切线切点最远的哪个点是最优的。

2017

对于Bi来说,Bj和Bk都是可选点。但是显然Bk是比较优的。于是找到每个点的nxt之后。只需要知道转一圈需要最少几个点就好了。于是问题n^2就已经可以解决了。但是其实可以更快。比如找nxt那块可以O(n).然后整体复杂度可以减少到nlogn.

其中代码是由@Alwayswet写的,可以看到只需要0ms就可以通过该题目了。

#include 
using namespace std;

struct Pnt {
  int x, y;
  Pnt() {}
  Pnt(int x, int y) : x(x), y(y) {}
  Pnt operator-(const Pnt& a) {
    return Pnt(x - a.x, y - a.y);
  }
  int operator*(const Pnt& a) {
    return x * a.y - y * a.x;
  }
  int operator^(const Pnt& a) {
    return x * a.x + y * a.y;
  }
  bool operator==(const Pnt& a) {
    return x == a.x && y == a.y;
  }
  void input() {
    cin >> x >> y;
  }
} p[505], q[505], res[505];

double mult(Pnt sp, Pnt ep, Pnt op) {
  return (sp.x - op.x) * (ep.y - op.y) - (ep.x - op.x) * (sp.y - op.y);
}
bool operator<(const Pnt &l, const Pnt &r) {
  return l.y < r.y || (l.y == r.y && l.x < r.x);
}
int graham(Pnt pnt[], int n, Pnt res[]) {
  int i, len, top = 1;
  sort(pnt, pnt + n);
  if(n == 0) return 0;
  res[0] = pnt[0];
  if(n == 1) return 1;
  res[1] = pnt[1];
  if(n == 2) return 2;
  res[2] = pnt[2];
  for(i = 2; i < n; ++i) {
    while(top && mult(pnt[i], res[top], res[top - 1]) >= 0) --top;
    res[++top] = pnt[i];
  }
  len = top;
  res[++top] = pnt[n - 2];
  for(i = n - 3; i >= 0; --i) {
    while(top != len && mult(pnt[i], res[top], res[top - 1]) >= 0) --top;
    res[++top] = pnt[i];
  }
  return top;
}

bool pnt_on_seg(Pnt p, Pnt l1, Pnt l2) {
  return ((l1 - p) * (l2 - p)) == 0 && ((l1 - p) ^ (l2 - p)) <= 0;
}

int pnt_in_ploy(Pnt tp[], int n, Pnt pnt) {
  for(int i = 0; i < n; ++i) {
    int s = (pnt - tp[i]) * (tp[i + 1] - tp[i]);
    if(s == 0) return 0;
    if(pnt == tp[i]) return 2;
    if(s > 0) return -1;
  }
  return 1;
}

bool check(Pnt tp[], int n, Pnt pt[], int m) {
  for(int i = 0; i < n; ++i) {
    if(pnt_in_ploy(pt, m, tp[i]) < 0) return false;
  }
  return true;
}

bool judge(Pnt u, Pnt v, Pnt p1, Pnt p2, int tag) {
  if(tag) return (p1 - u) * (v - u) <= 0 && (p2 - u) * (v - u) < 0;
  else return (p1 - u) * (v - u) <= 0 && (p2 - u) * (v - u) <= 0;
}

int seg_inter_seg(Pnt a, Pnt b, Pnt c, Pnt d) {
  int s1, s2, s3, s4;
  int d1, d2, d3, d4;
  d1 = (s1 = (b - a) * (c - a));
  d2 = (s2 = (b - a) * (d - a));
  d3 = (s3 = (d - c) * (a - c));
  d4 = (s4 = (d - c) * (b - c));
  if((d1 ^ d2) == -2 && (d3 ^ d4) == -2) {
    return 1;
  }
  if(d1 == 0 && ((a - c) ^ (b - c)) <= 0) {
    return 2;
  }
  if(d2 == 0 && ((a - d) ^ (b - d)) <= 0) {
    return 2;
  }
  if(d3 == 0 && ((c - a) ^ (d - a)) <= 0) {
    return 2;
  }
  if(d4 == 0 && ((c - b) ^ (d - b)) <= 0) {
    return 2;
  }
  return 0;
}

int gao(Pnt tp[], int n, Pnt pt[], int m, int tag) {
  int mp[505], nxt[505];
  memset(mp, -1, sizeof(mp));
  for(int i = 0; i < n; ++i) {
    for(int j = 0; j < m; ++j) {
      if(judge(tp[i], pt[j], pt[(j - 1 + m) % m], pt[j + 1], tag)) {
        mp[i] = j;
      }
    }
  }
  for(int i = 0; i < n; ++i) {
    nxt[i] = -1;
    Pnt u = tp[i], v = pt[mp[i]];
    for(int j = 0; j < n; ++j) if(i != j) {
        if((tp[j] - u) * (v - u) >= 0) {
          if(nxt[i] == -1) {
            nxt[i] = j;
          } else {
            int k1 = mp[j], k2 = mp[nxt[i]];
            if(k1 < mp[i]) k1 += m;
            if(k2 < mp[i]) k2 += m;
            if(k1 >= k2) nxt[i] = j;
          }
        }
      }
    if(nxt[i] == -1) while(true);
  }
  int ans = 111111;
  for(int i = 0; i < n; ++i) {
    int cnt = 1, now = i;
    int num = 1;
    while(true) {
      num += (m + mp[nxt[now]] - mp[now]) % m;
      now = nxt[now], ++cnt;
      if(!tag) {
        if(num >= m && num >= 3) {
          if(!seg_inter_seg(tp[i], tp[now], pt[0], pt[1])) break;
        }
      } else if(num >= m) break;
    }
    ans = min(ans, cnt);
  }
  return ans;
}

int update(Pnt tp[], int n, Pnt pt[], int m) {
  int M = 0;
  for(int i = 0; i < m; ++i) {
    if(pnt_in_ploy(tp, n, pt[i]) != 1) res[M ++] = pt[i];
  }
  for(int i = 0; i < M; ++i) q[i] = res[i];
  q[M] = q[0];
  return M;
}

int main() {
  int n, m, M;
  while(cin >> n) {
    for(int i = 0; i < n; ++i) p[i].input();
    n = graham(p, n, res);
    for(int i = 0; i < n; ++i) p[i] = res[i];
    p[n] = p[0];
    cin >> m;
    M = m;
    for(int i = 0; i < m; ++i) q[i].input();
    m = graham(q, m, res);
    for(int i = 0; i < m; ++i) q[i] = res[i];
    q[m] = q[0];
    if(n == 1) {
      if(m == 1) {
        if(p[0] == q[0]) cout << M - 1 << endl;
        else cout << "ToT" << endl;
      } else if(m == 2) {
        if(pnt_on_seg(p[0], q[0], q[1])) cout << M - 2 << endl;
        else if(p[0] == q[0] || p[0] == q[1]) cout << M - 1 << endl;
        else cout << "ToT" << endl;
      } else {
        int k = pnt_in_ploy(q, m, p[0]);
        if(k == 0) cout << M - 2 << endl;
        else if(k == 1) cout << M - 3 << endl;
        else if(k == 2) cout << M - 1 << endl;
        else cout << "ToT" << endl;
      }
    } else if(n == 2) {
      if(m == 1) {
        cout << "ToT" << endl;
      } else if(m == 2) {
        if(pnt_on_seg(p[0], q[0], q[1]) && pnt_on_seg(p[1], q[0], q[1]))
          cout << M - 2 << endl;
        else cout << "ToT" << endl;
      } else {
        int k1 = pnt_in_ploy(q, m, p[0]);
        int k2 = pnt_in_ploy(q, m, p[1]);
        if(k1 < 0 || k2 < 0) cout << "ToT" << endl;
        else cout << M - gao(q, m, p, n, 0) << endl;
      }
    } else {
      if(m <= 2) {
        cout << "ToT" << endl;
      } else if(!check(p, n, q, m)) {
        cout << "ToT" << endl;
      } else {
        m = update(p, n, q, m);
        cout << M - gao(q, m, p, n, 1) << endl;
      }
    }
  }
  return 0;
}


你可能感兴趣的:(几何)