传送门:
codevs1273
zoj1562
codevs1273
将点按极角排序, g [ i ] [ j ] g[i][j] g[i][j]表示点 i , j i,j i,j和基点围成的三角形内所有点的总价值。 d p [ i ] [ j ] dp[i][j] dp[i][j]表示凸包从基点出发顺时针最后两个点分别为 j , i j,i j,i时的最优答案。
暴力处理 g , d p g,dp g,dp复杂度 O ( n 3 ) O(n^3) O(n3)。
优化:
求解
g
[
i
]
[
j
]
g[i][j]
g[i][j]时,首先固定
i
i
i,
[
i
+
1
,
n
]
[i+1,n]
[i+1,n]逐个枚举
j
j
j,按
i
i
i到
j
j
j的极角大小为权值加入平衡树,
g
[
i
]
[
j
]
g[i][j]
g[i][j]就是平衡树中在
j
j
j左边的所有点的总值。复杂度
O
(
n
2
log
n
)
O(n^2\log n)
O(n2logn)
d p dp dp时枚举中转点,将所有前驱 j j j按 i → j i\to j i→j极角大小插入 b s t bst bst,维护子树 m a x ( f [ j ] [ i ] ) max(f[j][i]) max(f[j][i]),对于所有后继按反向极角二分插入查询最大值即可。复杂度 O ( n 2 log n ) O(n^2\log n) O(n2logn)
代码
暴力 O ( n 3 ) O(n^3) O(n3)
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int N=105;
struct P{
int x,y,t;
P(int _x=0,int _y=0):x(_x),y(_y){}
inline P operator - (const P&ky){return P(x-ky.x,y-ky.y);}
inline ll operator * (const P&ky){return (ll)x*ky.y-(ll)y*ky.x;}
inline bool operator < (const P&ky)const{return atan2(y,x)<atan2(ky.y,ky.x);}
}p[N];
int n,m,ans,g[N][N],f[N][N];
int main(){
int i,j,k,v;
scanf("%d%d",&n,&m);
for(i=1;i<=n;++i) scanf("%d%d",&p[i].x,&p[i].y),p[i].t=1;
for(i=n+1;i<=n+m;++i) scanf("%d%d",&p[i].x,&p[i].y),p[i].t=-1;
n+=m;sort(p+1,p+n+1);
for(i=1;i<=n;++i)
for(j=i+1;j<=n;++j)
for(k=i+1;k<j;++k)
if((p[i]-p[k])*(p[j]-p[k])>0) g[i][j]+=p[k].t;
for(i=1;i<=n;++i){
f[i][0]=p[i].t;
for(j=1;j<i;++j){
for(v=k=0;k<j;++k)
if((p[k]-p[i])*(p[j]-p[i])>=0)
v=max(v,f[j][k]+g[j][i]+p[i].t);
ans=max(ans,(f[i][j]=v));
}
}
printf("%d",ans);
return 0;
}
ZOJ1562
套上一个枚举起点,
g
[
i
]
[
j
]
g[i][j]
g[i][j]该为与
(
i
,
j
)
(i,j)
(i,j)与起点围成三角形中是否存在障碍物。
其余同上。复杂度
O
(
n
4
)
O(n^4)
O(n4)或
O
(
n
3
log
n
)
O(n^3\log n)
O(n3logn)