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

躲猫猫社团团长 http://t.sina.com.cn/coolria

原文地址:https://www.cnblogs.com/yangyh/p/2073762.html