BZOJ1591 USACO 2008 Dec Gold 4.Largest Fence Solution
2014-09-17 14:54
393 查看
题目大意:
求出平面上n个点组成的一个包含顶点数最多的凸多边形。n<=250.
Sol:
首先考虑O(n^4)算法。
将所有点按照水平序排序。
首先枚举最左侧的点,考虑在这种情况下down[i][j](表示最右侧的两个点为i,j)下凸壳上的最大点数。
与之同理,枚举最右侧的点,考虑此时up[i][j](表示最左侧的点i,j)上凸壳上的最大点数。
此时状态O(n^2),转移O(n),n次dp,总复杂度为O(n^4).
对于答案,我们只需枚举左右两个端点,O(n)合并dp最优值即可。总复杂度为O(n^3).
因此,总的时间复杂度为O(n^4).
代码如下:
显然状态已经没有办法再优化了。那么转移能否优化呢?
首先考虑能否优化到O(logn).
我们可以预处理出所有点关于先加入的点的极角序,利用树状数组,询问、更新均只需要O(logn)。
于是总的时间复杂度变为O(n^3logn).
然而,我们还能做的更好!
我们考虑换一个状态,比如将枚举y坐标最小的点,然后将合法的点按照关于它的极角序排序。
我们按照极角序进行dp.
将状态变为dp[i][j]表示i为最后一个加入的点,j为下一个尝试加入的点。
那么可以存在两种向下转移的方式:
若加入j,则dp[j][f(i,j)]=dp[i][j]+1,其中f(i,j)表示i指向j的射线逆时针旋转角度最近的某个点。
若不加入j,则dp[i][g(i,j)]=dp[i][j],其中g(i,j)所有点按照关于点i的极角序排序j的下一个点。
我们可以事先利用O(n^3)的复杂度完成f,g的预处理。
那么现在的状态O(n^3),转移O(1)。
于是总的时间复杂度为O(n^3),完美解决了此题。
代码还待填坑。
求出平面上n个点组成的一个包含顶点数最多的凸多边形。n<=250.
Sol:
首先考虑O(n^4)算法。
将所有点按照水平序排序。
首先枚举最左侧的点,考虑在这种情况下down[i][j](表示最右侧的两个点为i,j)下凸壳上的最大点数。
与之同理,枚举最右侧的点,考虑此时up[i][j](表示最左侧的点i,j)上凸壳上的最大点数。
此时状态O(n^2),转移O(n),n次dp,总复杂度为O(n^4).
对于答案,我们只需枚举左右两个端点,O(n)合并dp最优值即可。总复杂度为O(n^3).
因此,总的时间复杂度为O(n^4).
代码如下:
#include <cstdio> #include <cstring> #include <cctype> #include <iostream> #include <algorithm> using namespace std; #define N 251 struct Point { int x, y; Point(int _x = 0, int _y = 0):x(_x),y(_y){} bool operator < (const Point &B) const { return x < B.x || (x == B.x && y < B.y); } Point operator - (const Point &B) const { return Point(B.x - x, B.y - y); } void read() { scanf("%d%d", &x, &y); } }S ; int Cross(const Point &A, const Point &B) { return A.x * B.y - A.y * B.x; } bool judge(const int &i, const int &j, const int &k) { return Cross(S[i] - S[j], S[j] - S[k]) > 0; } int down , up , s_down , s_up ; int main() { int n; scanf("%d", &n); int i, j, k; for(i = 1; i <= n; ++i) S[i].read(); sort(S + 1, S + n + 1); memset(s_down, 0xef, sizeof(s_down)); memset(s_up, 0xef, sizeof(s_up)); for(int begin = 1; begin < n; ++begin) { memset(down, 0xef, sizeof(down)); for(j = begin + 1; j <= n; ++j) down[begin][j] = 2; for(j = begin + 1; j <= n; ++j) { for(i = begin + 1; i < j; ++i) { for(k = begin; k < i; ++k) { if (judge(k, i, j)) down[i][j] = max(down[i][j], down[k][i] + 1); } } } for(j = begin + 1; j <= n; ++j) for(i = begin; i < j; ++i) s_down[begin][j] = max(s_down[begin][j], down[i][j]); } for(int end = n; end > 1; --end) { memset(up, 0xef, sizeof(up)); for(j = 1; j < end; ++j) up[end][j] = 2; for(j = end - 1; j >= 1; --j) { for(i = j + 1; i < end; ++i) { for(k = i + 1; k <= end; ++k) { if (judge(k, i, j)) up[i][j] = max(up[i][j], up[k][i] + 1); } } } for(j = end - 1; j >= 1; --j) for(i = j + 1; i <= end; ++i) s_up[end][j] = max(s_up[end][j], up[i][j]); } int res = 0; for(i = 1; i <= n; ++i) for(j = i + 1; j <= n; ++j) res = max(res, s_down[i][j] + s_up[j][i]); printf("%d", res - 2); return 0; }
显然状态已经没有办法再优化了。那么转移能否优化呢?
首先考虑能否优化到O(logn).
我们可以预处理出所有点关于先加入的点的极角序,利用树状数组,询问、更新均只需要O(logn)。
于是总的时间复杂度变为O(n^3logn).
然而,我们还能做的更好!
我们考虑换一个状态,比如将枚举y坐标最小的点,然后将合法的点按照关于它的极角序排序。
我们按照极角序进行dp.
将状态变为dp[i][j]表示i为最后一个加入的点,j为下一个尝试加入的点。
那么可以存在两种向下转移的方式:
若加入j,则dp[j][f(i,j)]=dp[i][j]+1,其中f(i,j)表示i指向j的射线逆时针旋转角度最近的某个点。
若不加入j,则dp[i][g(i,j)]=dp[i][j],其中g(i,j)所有点按照关于点i的极角序排序j的下一个点。
我们可以事先利用O(n^3)的复杂度完成f,g的预处理。
那么现在的状态O(n^3),转移O(1)。
于是总的时间复杂度为O(n^3),完美解决了此题。
代码还待填坑。
相关文章推荐
- BZOJ1591 & 洛谷2924:[USACO2008 DEC]Largest Fence 最大的围栏——题解
- BZOJ 2606 USACO 2008 Dec Gold 2.Secret Message 字典树
- 【BZOJ1589】【USACO 2008 Dec Gold】 1.Trick or Treat on the Farm 基环树裸DP、
- Bzoj1591:[Usaco2008 Dec]Largest Fence 最大的围栏:DP
- [BZOJ1590] [Usaco2008 Dec]Secret Message 秘密信息(字典树)
- 【bzoj1606】[Usaco2008 Dec]Hay For Sale 购买干草 背包dp
- BZOJ1606: [Usaco2008 Dec]Hay For Sale 购买干草
- [bzoj 1607] [Usaco2008 Dec]Patting Heads 轻拍牛头 筛数
- BZOJ-1607 [Usaco2008 Dec]Patting Heads 轻拍牛头 筛法+乱搞
- 【BZOJ】1606: [Usaco2008 Dec]Hay For Sale(背包)
- [bzoj 1606] [Usaco2008 Dec]Hay For Sale 购买干草 (dp)
- bzoj 1607: [Usaco2008 Dec]Patting Heads 轻拍牛头 筛法
- BZOJ 1589: [Usaco2008 Dec]Trick or Treat on the Farm 采集糖果
- BZOJ1590 [Usaco2008 Dec]Secret Message 秘密信息
- bzoj 1607: [Usaco2008 Dec]Patting Heads 轻拍牛头
- BZOJ1577 USACO 2009 Feb Gold 1.Fair Shuttle Solution
- BZOJ3387 [USACO2004 Dec] Fence Obstacle Course栅栏行动
- 【BZOJ】1607: [Usaco2008 Dec]Patting Heads 轻拍牛头(特殊的技巧)
- BZOJ 1590: [Usaco2008 Dec]Secret Message 秘密信息 Trie树
- bzoj千题计划161:bzoj1589: [Usaco2008 Dec]Trick or Treat on the Farm 采集糖果