Codeforces 599E Sandy and Nuts(状压DP)
题目链接 Sandy and Nuts
题意大概就是给出限制条件求出在该限制条件下树的种数。
#include <bits/stdc++.h> using namespace std; #define REP(i, n) for (int i(0); i < (n); ++i) #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) typedef long long LL; const int N = 15; const int maxS = 10010; const int maxQ = 210; int n, m, q, all; LL f[N][maxS]; int a[maxQ], b[maxQ], c[maxQ]; int e[N][N]; inline in(int i, int S){ return (S >> i) & 1; } LL DP(int u, int S){ LL &ret = f[u][S]; if (ret != -1) return ret; ret = 0; int St = S ^ (1 << u); int t; for (t = 0; t < n; ++t) if (in(t, St)) break; for (int __S = St; __S; (--__S) &= St) if (in(t, __S)){ bool flag = true; REP(i, n) if (i != u){ REP(j, n) if (j != u){ if (e[i][j] && (in(i, __S) ^ in(j, __S))){ flag = false; break; } } if (!flag) break; } if (!flag) continue; int v, cnt = 0; REP(i, n){ if (e[u][i] && in(i, __S)){ ++cnt; v = i; } } if (cnt >= 2) continue; rep(i, 1, q){ if (c[i] == u && in(a[i], __S) && in(b[i], __S)){ flag = false; break; } if (in(c[i], __S) && (!in(a[i], __S) || !in(b[i], __S))){ flag = false; break; } } if (!flag) continue; if (cnt == 1) ret += DP(v, __S) * DP(u, S ^ __S); else REP(v, n) if (in(v, __S)) ret += DP(v, __S) * DP(u, S ^ __S); } return ret; } int main(){ scanf("%d%d%d", &n, &m, &q); rep(i, 1, m){ int x, y; scanf("%d%d", &x, &y); --x, --y; e[x][y] = e[y][x] = 1; } rep(i, 1, q){ scanf("%d%d%d", a + i, b + i, c + i); --a[i], --b[i], --c[i]; } all = (1 << n) - 1; memset(f, -1, sizeof f); REP(i, n) f[i][1 << i] = 1; return 0 * printf("%lld\n", DP(0, all)); }