集合划分(状压DP)

Posted jpphy0

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了集合划分(状压DP)相关的知识,希望对你有一定的参考价值。

问题

将n个整数分成若干组,并使得各组的数字之和为质数,求分组的方案数。

  • 1 ≤ n ≤ 15 1\\leq n \\leq 15 1n15
  • 整数 a i a_i ai 满足 1 ≤ a i ≤ 99 1\\leq a_i \\leq 99 1ai99

分析

代码

/* 集合划分 状压dp */
#include<bits/stdc++.h>
using namespace std;
const int MXS = (1<<15)+5;
const int MXN = 17;
int N, a[MXN], dp[MXS], sum[MXS]={0};
int c[MXS], p[1700] = {1, 1}; // 高位1的位置、是否质数
int main(){
	int t, T = 0, S;
	for(int i = 0; i < 15; ++i) c[1<<i] = i+1;
	for(int i = 2; i*i < 1700; ++i)
		for(int j = i<<1; j < 1700; j += i) p[j] = 1;
	scanf("%d", &t);	
	while(t--){
		scanf("%d", &N);			
		for(int i = 1; i <= N; ++i) scanf("%d", a+i);
		S = (1<<N)-1;
		for(int s = 1; s <= S; ++s){ // 枚举集合
			int ls = -s&s, hs = s^ls;
			if(ls == s) sum[s] = a[c[s]]; // 单个数字的组合
			else sum[s] = sum[hs] + sum[ls]; // 多个数字的组合
			dp[s] = p[sum[s]] == 0; // 集合不拆分是否质数
			for(int ss = hs; ss > 0; ss = (ss-1)&hs) // 枚举组合状态
				dp[s] += dp[ss]*(p[sum[ss^s]]==0);
		}
		printf("%d\\n", dp[(1<<N)-1]);
	}
    return 0;
}

以上是关于集合划分(状压DP)的主要内容,如果未能解决你的问题,请参考以下文章

Luogu4221 WC2018州区划分(状压dp+FWT)

HDU4057 Rescue the Rabbit(AC自动机+状压DP)

POJ1699 Best Sequence(AC自动机+状压DP)

HDU 5765 Bonds(状压DP)

18.06.03 POJ 4126:DNA 15年程设期末05(状压DP)

hdu 5418 Victor and World (状压dp)