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

 

转载于:https://www.cnblogs.com/cxhscst2/p/6804042.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值