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));
}

 

posted @ 2017-05-03 21:42  cxhscst2  阅读(373)  评论(0编辑  收藏  举报