POJ 1011/DFS:子集划分

问题描述:原有若干sticks,每支stick被分割成若干支,现在要恢复一下。找出这样的子集,使得每个子集的和(plen)相等,并且最小

算法:排序,遍历所有可能plen

剪枝:排序后, a[0] a[1] a[2].....a[n-1],如果想从a[i]开始(不包括i)匹配一个数v,如果i+1,i+2......n-1都匹配不成功了,则肯定i+2,i+3....n-1也匹配不成功了,所以从TLE版本做修改后得到AC版本

TLE:

#include <iostream>

#include <algorithm>

using namespace std;

#define MAX 64

int sticks[MAX];

bool used[MAX];

int stickNum,plen,n;



bool compare(int a, int b)

{

    return a > b;    

}

//从beginIndex号开始匹配,下一步要匹配matchLen的stick,在此之前已经匹配了hasMatch条stick

bool dfs(int beginIndex,int matchLen,int hasMatch){

	//printf("%4d%4d%4d\n",beginIndex,matchLen,hasMatch);

	if(matchLen==0){

		hasMatch++;

		//printf("hasMatch=%d,stickNum=%d\n",hasMatch,stickNum);	

		if(hasMatch==stickNum){

			//printf("hasMatch==stickNum\n");	

			return true;

		}

		for(beginIndex=0;used[beginIndex];beginIndex++);

		//used[beginIndex]=true;

		//printf("match=%d begin = %d\n",hasMatch,beginIndex);

		if(dfs(beginIndex,plen,hasMatch))return true;

		//used[beginIndex]=false;

		return false;

	

	}else{

		if(beginIndex>n-1)return false;

		for(int i=beginIndex;i<n;i++){

			if(used[i])continue;

			if(sticks[i]>matchLen)continue;

			if(i>0&&sticks[i]==sticks[i-1]&&!used[i-1])continue;

			used[i]=true;

			if(dfs(i+1,matchLen-sticks[i],hasMatch))

				return true;

			used[i]=false;

		}

	

	}

	//printf("end %4d%4d%4d false\n",beginIndex,matchLen,hasMatch);

	return false;



}

int main(int argc, char* argv[])

{

	

	int sum = 0;

	int i;

	while(scanf("%d",&n)&&n){

	

		sum=0;

		for( i=0;i<n;i++){

			scanf("%d",&sticks[i]);

			sum += sticks[i];

		}

		bool ok = false;

		sort(sticks,sticks+n,compare);

		

		for(plen=sticks[0];plen<=sum/2;plen++){

			if(sum%plen==0){

				

				//used[0]=true;

				stickNum = sum/plen;

				if(dfs(0,plen,0)){

					ok = true;

					break;

				}

				//used[0]=false;

			}



		}

		if(ok){

			printf("%d\n",plen);



		}else{

			printf("%d\n",sum);

		}

		memset(used,false,sizeof(used));

	}

	

	return 0;

}

AC:

#include <iostream>

#include <algorithm>

using namespace std;

#define MAX 64

int sticks[MAX];

bool used[MAX];

int stickNum,plen,n;



bool compare(int a, int b)

{

    return a > b;    

}

//从beginIndex号开始匹配,下一步要匹配matchLen的stick,在此之前已经匹配了hasMatch条stick

bool dfs(int beginIndex,int matchLen,int hasMatch){

	//printf("%4d%4d%4d\n",beginIndex,matchLen,hasMatch);

	if(matchLen==0){

		hasMatch++;

		//printf("hasMatch=%d,stickNum=%d\n",hasMatch,stickNum);	

		if(hasMatch==stickNum){

			//printf("hasMatch==stickNum\n");	

			return true;

		}

		for(beginIndex=0;used[beginIndex];beginIndex++);

		

		//printf("match=%d begin = %d\n",hasMatch,beginIndex);

		used[beginIndex]=true;

		if(dfs(beginIndex+1,plen-sticks[beginIndex],hasMatch))return true;

		used[beginIndex]=false;

		return false;

	

	}else{

		if(beginIndex>n-1)return false;

		for(int i=beginIndex;i<n;i++){

			if(used[i])continue;

			if(sticks[i]>matchLen)continue;

			if(i>0&&sticks[i]==sticks[i-1]&&!used[i-1])continue;

			used[i]=true;

			if(dfs(i+1,matchLen-sticks[i],hasMatch))

				return true;

			used[i]=false;

		}

	

	}

	//printf("end %4d%4d%4d false\n",beginIndex,matchLen,hasMatch);

	return false;



}

int main(int argc, char* argv[])

{

	//freopen("i://in.txt","r",stdin);

	int sum = 0;

	int i;

	while(scanf("%d",&n)&&n){

		

		sum=0;

		for( i=0;i<n;i++){

			scanf("%d",&sticks[i]);

			sum += sticks[i];

		}

		bool ok = false;

		sort(sticks,sticks+n,compare);

		

		for(plen=sticks[0];plen<=sum/2;plen++){

			if(sum%plen==0){

				

				used[0]=true;

				stickNum = sum/plen;

				if(dfs(0,plen-sticks[0],0)){

					ok = true;

					break;

				}

				used[0]=false;

			}

			

		}

		if(ok){

			printf("%d\n",plen);

			

		}else{

			printf("%d\n",sum);

		}

		memset(used,false,sizeof(used));

	}

	

	return 0;

}

你可能感兴趣的:(poj)