Codeforces 1146H. Satanic Panic(极角排序+DP)
Codeforces 1146H. Satanic Panic
题目大意
- 给出平面内的 N N N个点,求多少种方案能选择五个点构成一个“五角星”。这里的“五角星”不一定要每条边相同,但要保证该线段之间该相交的地方要相交(脑补一下正常五角星的形状)。
- N ≤ 300 N≤300 N≤300
题解
- 首先可以想到转换一下题意,要求的是五角星,不太好统计,不妨可以把每个五角星对应成五个点顺次连接形成的凸包,也很显然每个五个点的凸包和五角星都是一一对应的,于是我们可以求这样的凸包数量。
- 考虑到凸包每条边的极角是依次递增的,所以不妨先把边连出来,一共 N ( N − 1 ) N(N-1) N(N−1)条边(顶点相同方向不同也算不同),接着按照它们对应的向量的极角进行排序,用DP求方案数。
- 设 f i , j , k f_{i,j,k} fi,j,k表示以 i i i为起点,凸包第 k k k个点是 j j j的方案数,显然有转移
- f i , i , 0 = 1 f_{i,i,0}=1 fi,i,0=1
- f i , j , k = ∑ ( j ′ , j ) ∈ E f i , j ′ , k − 1 f_{i,j,k}=\sum_{(j',j)\in E} f_{i,j',k-1} fi,j,k=(j′,j)∈E∑fi,j′,k−1
- 由于需要保证加入的每条边极角是递增的,所以要先枚举边再转移。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define N 310
#define ld long double
#define ll long long
struct node{
int x, y;
ld d;
}a[N], e[N * N];
ll f[N][N][6];
int cmp(node x, node y) {
return x.d < y.d;
}
int main() {
int n, i, j, l;
scanf("%d", &n);
for(i = 1; i <= n; i++) {
scanf("%d%d", &a[i].x, &a[i].y);
}
int tot = 0;
for(i = 1; i <= n; i++)
for(j = 1; j <= n; j++) if(i != j) {
e[++tot].x = i, e[tot].y = j;
e[tot].d = atan2(a[j].y - a[i].y, a[j].x - a[i].x);
}
sort(e + 1, e + tot + 1, cmp);
for(i = 1; i <= n; i++) f[i][i][0] = 1;
for(i = 1; i <= tot; i++) {
for(j = 1; j <= n; j++) {
for(l = 0; l < 5; l++) {
f[j][e[i].y][l + 1] += f[j][e[i].x][l];
}
}
}
ll ans = 0;
for(i = 1; i <= n; i++) ans += f[i][i][5];
printf("%lld", ans);
return 0;
}
哈哈哈哈哈哈哈哈哈哈

浙公网安备 33010602011771号