zoukankan      html  css  js  c++  java
  • [CF852H]Bob and stages

    题意:给出平面上(n)个点,要求选出(k)个点,使得这些点形成一个凸包,且凸包内部没有点,求最大面积。无解输出(0)

    题解:枚举凸包最左的点(p),删除所有在(p)左边的点,然后把(p)定为原点。将所有点按极角排序,相邻两个点之间连边,那么会形成一个星状多边形,合法的凸包一定在这个多边形内部。

    先考虑求出这张图的visibility graph,显然合法的凸包所有边都是visibility graph上的边。求法大概是逆时针枚举所有点,对于每个点维护一个队列维护未来可能加入的边,实际上是对于每个点(i),维护所有满足(ij)在visibility graph上,并且当前还没找到(k(k>i))使得(jk)在visibility graph上的(j),详见代码。复杂度(O(E))

    考虑在visibility graph上DP。顺时针枚举所有点,设(f_{i,j,k})表示最后一条选取的边为(i,j),选了(k)条边的最大面积。转移时可以枚举一个(l),如果(i,j)(l,i)这两条边可以同时存在(不会使得凸包不满足凸性)则可以转移到(f_{l,i,k+1})。朴素DP复杂度(O(n^3k)),可以对于每个点将转移出去和进来的边分别排序后(其实根据求visibility graph的过程,这些边是已经排好序的)双指针+前缀和优化,复杂度(O(n^2k))

    总复杂度(O(n^3k))

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 210;
    typedef long long ll;
    typedef double db;
    #define pb push_back
    
    int gi() {
      int x = 0, o = 1;
      char ch = getchar();
      while((ch < '0' || ch > '9') && ch != '-') {
        ch = getchar();
      }
      if(ch == '-') {
        o = -1, ch = getchar();
      }
      while(ch >= '0' && ch <= '9') {
        x = x * 10 + ch - '0', ch = getchar();
      }
      return x * o;
    }
    
    struct point {
      int x, y;
      db k;
      point(int x = 0, int y = 0): x(x), y(y) {
        k = atan2(y, x);
      }
      point operator-(const point &A) const {
        return point(x - A.x, y - A.y);
      }
      ll operator%(const point &A) const {
        return 1ll * x * A.y - 1ll * y * A.x;
      }
      bool operator<(const point &A) const {
        return k < A.k;
      }
    } a[N], p[N];
    
    int n, m, tt;
    ll f[N][N][55], mx[55], ans = 0;
    queue<int> q[N];
    vector<int> E[N], G[N];
    
    void add(int x, int y) {
      while(!q[x].empty() && (p[q[x].front()] - p[x]) % (p[y] - p[x]) < 0) {
        add(q[x].front(), y), q[x].pop();
      }
      G[x].pb(y), E[y].pb(x), q[y].push(x);
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
      freopen("a.in", "r", stdin);
      freopen("a.out", "w", stdout);
    #endif
      cin >> n >> m;
      for(int i = 1; i <= n; i++) {
        a[i].x = gi(), a[i].y = gi();
      }
      for(int s = 1; s <= n; s++) {
        tt = 0;
        for(int i = 1; i <= n; i++) if(a[i].x > a[s].x || (a[i].x == a[s].x && a[i].y > a[s].y)) {
            p[++tt] = a[i] - a[s];
          }
        sort(p + 1, p + tt + 1);
        for(int i = 1; i <= tt; i++) {
          E[i].clear(), G[i].clear();
          while(!q[i].empty()) {
            q[i].pop();
          }
        }
        for(int i = 1; i < tt; i++) {
          add(i, i + 1);
        }
        memset(f, 0xc0, sizeof(f));
        for(int i = tt; i; i--) {
          memset(mx, 0xc0, sizeof(mx));
          reverse(E[i].begin(), E[i].end());
          int cur = G[i].size() - 1;
          for(auto j : E[i]) {
            f[i][j][1] = p[j] % p[i];
            while(~cur && (p[j] - p[i]) % (p[G[i][cur]] - p[i]) < 0) {
              for(int k = 1; k < m; k++) {
                mx[k] = max(mx[k], f[G[i][cur]][i][k]);
              }
              --cur;
            }
            for(int k = 1; k < m; k++) {
              f[i][j][k + 1] = mx[k] + p[j] % p[i];
            }
          }
        }
        for(int i = 1; i <= tt; i++)
          for(auto j : E[i]) {
            ans = max(ans, f[i][j][m - 2]);
          }
      }
      printf("%.2lf
    ", 1.0 * ans / 2);
      return 0;
    }
    
    
  • 相关阅读:
    NTC3950-10K温度传感器
    Maven常用命令:
    Linux-IIC驱动(详解)
    sourceinsight4 用设置
    LTDC/DMA2D—液晶显示***
    STM32F429的LTDC和DMA2D ***
    python机器学习sklearn 岭回归(Ridge、RidgeCV)
    random_state 参数
    python3 文件及文件夹路径相关
    机器学习:简单线性回归
  • 原文地址:https://www.cnblogs.com/gczdajuruo/p/10922492.html
Copyright © 2011-2022 走看看