HDU-1258 Sum It Up DFS

  给定一个非递减的序列,要求从这些序列中找出一系列的数相加等于要求的数。这题的主要任务就是怎样去重。

  现分析如下:

  对于给定的两个非递减序列,A, B, C, D 用来映射各个数的位置,2(A) 1(B) 1(C) 1(D) 以及 2(A) 2(B) 2(C) 1(D), 要求求出和为3的表达式。 显然前面的序列递归下去会首先出现A+ B的组合,由于此时A+ B已经等于了3,所以递归就会回溯,此时会形成A+ C的组合,按照正常人的思维,这个解肯定是不能够取的,但是计算机有这么聪明吗?显然还是要我们来设计各种复杂的判断...... 转回正题,我们在递归时有一个属性就是递归的层数,而该题的求解就会与这个层数扯上关系,对于两个相邻且大小相等的点是要特殊考虑的,为什么呢,从上面给定的两个序列可以看出来,(重复就是因为这些相同的数字带来的),而且这个序列是已经相当于排好序的,这点同样很重要。那么对于相同的数(同样一定会是相邻的)在深入的递归过程中是可以取的(可以理解为此时的和还未等于要求值,相同的数仍有利用价值)。那么对于同一层的相同数呢,呵呵,这是不能够取的,为什么呢?首先对于该种组合的状态是不是已经搜索过了,唯一有变化的就是所剩数字的差别了,在此而言,就是相对与上一相同的状态少了这个数而已。这样可能比较抽象,就拿 2 2 2 1 这个序列来说吧,2与后面的2都不能组合,因为其值超过了限定值3,最后和1组合即 A+ D= 3,对于第二个2 即B, 此时B与A是同一层的递归下,如果取 B 的话,那么同当时取 A 就一样了,都是在接下来的序列中寻找和为(3- 2)的组合,然而上次的选择范围是(B, C, D)三个数,这次只剩下(C, D)两个数了,所以可以得出上次搜索的解一定包括这次去搜索得到的解,因此就出现重复了。证毕。

  代码如下:

#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;

int t, n, num[105], rec[105];

void DFS( int sum, int pos, int cnt, int &ans )
{
	if( sum== t )
	{
	    ans= 1;
		for( int i= 1; i<= cnt; ++i )
		{
			printf( i== 1? "%d": "+%d", num[ rec[i] ] );
		}
		puts( "" );
		return;
	}
	for( int i= pos+ 1; i<= n; ++i )
	{ 
	    if( num[i]!= num[i- 1]|| i== pos+ 1 )
	    {
	    // 前面的就是判定同一层不能计算相邻且大小相等的数,后面的处理不同层的相邻的相同的数
		    if( t>= sum+ num[i] )
		    {
			    rec[cnt+ 1]= i;
			    DFS( sum+ num[i], i, cnt+ 1, ans );
		    }
	    }
	}
}

int main()
{
	while( scanf( "%d %d", &t, &n ), t| n )
	{
	    int ans= 0;
	    num[0]= -1;
		for( int i= 1; i<= n; ++i )
		{
			scanf( "%d", &num[i] );
		}
		printf( "Sums of %d:\n", t );
		DFS( 0, 0, 0, ans );
		if( !ans )
		{
		    puts( "NONE" );
		}
	}
	return 0;
}
posted @ 2011-08-12 11:35  沐阳  阅读(419)  评论(0编辑  收藏  举报