[CQOI2018]解锁屏幕
这图太毒瘤了, 看了几遍看不懂。
直接状压, dp(S,i) 表示走完了集合 S, 停在 i 的方案数。
计算几何水平缺失(
#include <bits/stdc++.h>
using namespace std;
const int mo = 1e8 + 7;
int n;
struct point { int x, y;} p[21];
bool is (point a, point b, point c) {
return (b.y - a.y) * (c.x - b.x) == (b.x - a.x) * (c.y - b.y);
}
int pop_count[1 << 20], nd[21][21];
int dp[1 << 20][20];
int main()
{
scanf ("%d", & n);
for (int i = 0; i < n; ++ i)
scanf ("%d%d", & p[i].x, & p[i].y);
for (int i = 1; i < (1 << n); ++ i)
pop_count[i] = pop_count[i >> 1] + (i & 1);
for (int i = 0; i < n; ++ i)
for (int j = 0; j < n; ++ j)
{
if (i == j) continue;
for (int k = 0; k < n; ++ k)
{
if (i == k || j == k) continue;
if (((p[k].x-p[i].x) * (p[k].x-p[j].x)<0||(p[k].y-p[i].y) * (p[k].y-p[j].y)<0) && is (p[i], p[k], p[j])) nd[i][j] |= 1 << k;
}
}
long long ans = 0ll;
for (int i = 0; i < n; ++ i)
dp[1 << i][i] = 1;
for (int i = 1; i < (1 << n); ++ i)
{
for (int j = 0; j < n; ++ j)
if (dp[i][j] && ((i>>j) & 1))
{
if (pop_count[i] >= 4) ans += dp[i][j], ans %= mo;
for (int k = 0; k < n; ++ k)
if (((i>>k) & 1) == 0 && (nd[j][k] & i) == nd[j][k])
dp[i | (1 << k)][k] += dp[i][j], dp[i | (1 << k)][k] %= mo;
}
}
cout << ans;
return 0;
}