TopCoder SRM 574 Div1 Meidum PolygonTraversal
問題
正n多角形がある。
この多角形の頂点を折れ線で結んでいく。
いま、pointsで示される頂点を結んで、pointsの最後の頂点にいる。
残りまだ訪問してない頂点を、次の条件を満たすように結ぶ。
- 次の頂点への線分を描くとき、今までの折れ線に交差する。
- 最後の頂点から、pointsの一番最初の頂点への線分が、今までの折れ線に交差する
このとき、頂点の訪問の順番は何通りあるか、求めよ。
制約条件
N≦18
方針
bitDP.
dp[今までに訪問した頂点の番号][最後の頂点の番号]として、
これを更新していく。
最後の頂点から次に訪問できる頂点は、まず隣り合うところはダメ。
で、今までに訪問した頂点を一つでも超えたなら、交差をする。
逆に今までに訪問した頂点を超えないなら、交差しない。
なので、超えたところだけDPの更新をする。
それだけ。だけど本番中バグって時間かかってしまった。
ソースコード
const int mod = (int)1e9 + 7; int n; ll dp[1 << 18][18]; class PolygonTraversal { public: long long count(int N, vector <int> points) { memset(dp, 0, sizeof(dp)); int bit = 0; n = N; rep(i, points.size()) bit |= 1 << (points[i] - 1); dp[bit][points.back() - 1] = 1; rep(l, n - points.size()){ rep(i, 1 << n) if(__builtin_popcount(i) == l + points.size()) rep(p, n) if(dp[i][p]){ int j = p + 1, k = p + n - 1; for(; j < k && !(i & 1 << j % n); j++); for(; j < k && !(i & 1 << k % n); k--); for(; j < k; j++) if(!(i & 1 << j % n)){ dp[i | 1 << j % n][j % n] += dp[i][p]; } } } ll ans = 0; rep(i, n) if(i != (points[0] - 1 + 1) % n && i != (points[0] - 1 + n - 1) % n){ ans = ans + dp[(1 << n) - 1][i]; } return ans; } };