題意:
給出平面上n個點的坐標,選k個點,使得這k個點圍起來的面積最大.
分析:
參考了 叉姐的分析 和 不慌不忙菊苣的代碼
思路我都懂,但是DP的部分還是不太會寫.
我體會了一下其中含義,也許這樣可能會好理解一點:
因為求出來的凸包的點數是固定的,所能選的點數也是固定的,那么不選的點的數量也是固定的.
可以反過來考慮:少選一個點,就要損失凸包上的一塊面積.
假設\(d(i,j)\)表示考慮了前\(i\)個點,選了\(j\)個點,所損失的最少面積.
第\(i\)個點的前一個點是\(i'\),損失的面積為\(S_{cut}\),那么\(d(i,j)=min(d(i,j),d(i',j-1)+S_{cut})\)
最后答案就是凸包總面積減去最后損失的最小面積.
損失的面積是一小塊一小塊三角形累加起來的.
上個圖片僅供參考:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;typedef long long LL;const int maxn = 100 + 10;struct Point
{LL x, y;Point(LL x = 0, LL y = 0) : x(x), y(y) {}void read() { scanf("%lld%lld", &x, &y); }
};Point operator - (const Point& A, const Point& B) {return Point(A.x - B.x, A.y - B.y);
}bool operator < (const Point& A, const Point& B) {return A.x < B.x || (A.x == B.x && A.y < B.y);
}LL Cross(const Point& A, const Point& B) {return A.x * B.y - A.y * B.x;
}vector<Point> p, con;vector<Point> ConvexHull() {sort(p.begin(), p.end());int n = p.size();vector<Point> ch(n);int m = 0;for(int i = 0; i < n; i++) {while(m > 1 && Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2]) < 0) m--;ch[m++] = p[i];}int k = m;for(int i = n - 2; i >= 0; i--) {while(m > k && Cross(ch[m-1]-ch[m-2], p[i]-ch[m-2]) < 0) m--;ch[m++] = p[i];}if(n > 1) m--;ch.resize(m);return ch;
}int n, k;LL d[maxn][maxn];
bool vis[maxn];int main()
{//freopen("in.txt", "r", stdin);int _; scanf("%d", &_);for(int __ = 1; __ <= _; __++) {scanf("%d%d", &n, &k);p.resize(n);for(int i = 0; i < n; i++) p[i].read();con = ConvexHull();int sz = con.size();if(sz <= 2 || k <= 2) { printf("0\n"); continue; }LL totarea = 0;for(int i = 2; i < sz; i++) totarea += Cross(con[i-1]-con[0], con[i] - con[0]);if(k >= sz) {printf("%lld\n", totarea);continue;}LL ans = 0x3f3f3f3f3f3f3f3f;memset(vis, false, sizeof(vis));int times = min(10 * n / k, sz);while(times--) {int s = rand() % sz;while(vis[s]) s = rand() % sz;vis[s] = true;memset(d, 0x3f, sizeof(d));d[0][0] = 0;for(int i = 1; i <= sz; i++) {int p0 = (s + i) % sz;LL cut = 0;for(int j = i - 1; j >= 0; j--) {int p2 = (s + j) % sz;int p1 = (p2 + i) % sz;cut += Cross(con[p1] - con[p0], con[p2] - con[p0]);for(int l = k; l > 0; l--)d[i][l] = min(d[i][l], d[j][l-1] + cut);}}ans = min(ans, d[sz][k]);}printf("Case #%d: %lld\n", __, totarea - ans);}return 0;
}
轉載于:https://www.cnblogs.com/AOQNRMGYXLMV/p/4864442.html
總結
以上是生活随笔為你收集整理的HDU 5473 There was a kingdom 凸包 DP的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。