WOJ 1608 Calculation (暴力搜索/动态规划)

题意:

n个整数(n<=14),要求将这n个整数分成若干个部分,使得尽可能多的部分的数,可以通过加减法计算出S(0<=S<=10^8)。


输入:

第一行是T,代表测试数量。

接下来有T组数据,每组的第一行是n,第二行是n个数(0<=a[i]<=10^7)。


输出:

对于每一组数据,输出最多可以分成多少个可以计算出S的部分。


样例:

Sample Input
2
5 5
1 2 3 4 5
5 5
1 2 3 8 8
Sample Output
3
2



思路:

动态规划解法见这篇文章: http://blog.csdn.net/u014664226/article/details/51107676

我这里就讲讲暴力搜索的解法,n最大也才14,可以直接暴力搜索。


第一步:对于每一个子集(2^14个),计算出这个子集中的数能否计算出S,每个子集用14位的二进制数来表示。


第二步:按照最低的二进制位,对所有可以计算出S的子集进行分类,然后直接暴力搜索所有的可能性。


本题难度不大,主要是n太小了,导致暴力就可以做出来。值得一提的是F函数,F函数多次调用所需

的临时空间在外部已经申请好了(即D数组),代码中直接使用,避免了在F的内部调用的时候进行频繁地申请和释放。

计算出所有的Subset数组之后,需要按照最低位的1来分组,这时使用了指针来复用D数组的空间。


#include 
#include 
#include 
#include  
#include 
#include 
#include 
#include 
using namespace std;
int T;//T组数据 
int N;//N个数 
int S;//和为S 
int A[14];//N个数的值 
int D[1<<15];//临时空间 
int Subset[1<<14];//子集中的数能否计算出S 
int *aLow[14],nLow[14];//最低位为i的子集,存在于数组aLow[i]中,长度为nLow[i]。

void F(int i,int L,int R,int mask){ 
	//mask是14位的整数,表示目前集合的状态 
	//此时,i表示本次调用正在考虑是否往集合中加入A[i]
	//D数组中,下标为[L,R)的区间中存的是不加入A[i]的所有可能的计算结果 
	if(i==N) return;
	//如果不加 A[i],增加i,然后继续调用F 
	F(i+1,L,R,mask);
	//如果加入A[i],计算加入A[i]之后的所有可能的计算结果,存入D数组下标[2*L,2*R) 
	for(int t=L;t>j)&1){
					aLow[j][nLow[j]++]=i;
					break;
				}
			}
		} 
		//计算答案 
		int ANS=G(0,0,0);
		printf("%d\n",ANS);
	}
    return 0;  
} 



你可能感兴趣的:(WOJ 1608 Calculation (暴力搜索/动态规划))