ZOJ1909 POJ2362 HDU1518 Square,很经典的DFS+剪枝!

这题很经典的DFS+剪枝!我做了很久,DFS的回溯一直很混乱后来参考了这篇解题报告后顿时茅塞顿开!解题报告请猛击我!我的报告里面有对应的剪枝解释


/*******************************************************************************
 # Author : Neo Fung
 # Email : [email protected]
 # Last modified: 2011-10-19 21:29
 # Filename: ZOJ1909 POJ2362 HDU1518 Square.cpp
 # Description : 
 ******************************************************************************/
// #include "stdafx.h"
// #define DEBUG

#include <fstream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <memory.h>
#include <list>
#include <algorithm>
using namespace std;
int num[25],n;
bool visit[25];
int ave;

bool dfs(const int &rest,const int &sum,const int &cur)	//rest代表当前边的剩余长度, sum代表剩余木棍的总长度, cur记录当前的木棍
{
	if(sum==ave)	//到了这里代表已经找到三条边了,第四条边不用找了
		return true;

	for(int i=cur;i<n;++i)
	{
		if (num[i]==num[i-1] && !visit[i-1])	//如果这条边和上一条边的长度一样,且上一条边没有用上,那这条边减掉
			continue;

		if(!visit[i] && num[i]<=rest)
		{
			visit[i]=true;
			if(rest==num[i])		
			{
				//标记1,找到一条边后,进入下一条边
				if(dfs(ave,sum-rest,0))	
					return true;
			}
			else if( dfs( rest-num[i], sum-num[i],i))
				return true;
			visit[i]=false;

			//这个对应从标记1进入的状态,从头(0)开始找一条最长没有用过的边,如果这条边经过上面几步还是无法用到,则代表当初状态不可取
			if(rest==ave) return false;		
		}
	}
	return false;
}

int main(void)
{
#ifdef DEBUG  
	freopen("data.txt","r",stdin);  
#endif  
	int ncases;
	scanf("%d",&ncases);
	while(ncases--)
	{
		int sum=0;
		int maxlen=0;
		bool ans=false;
		scanf("%d",&n);
		for(int i=0;i<n;++i)
		{
			scanf("%d",&num[i]);
			sum+=num[i];
			maxlen = max(num[i],maxlen);	//求所有木棍中最长木棍
		}
		ave = sum/4;
		if(sum%4 || maxlen>ave)	//如果总的长度不能被4整除,或者最长木棍大于边长度,减掉
			goto end;

		memset(visit,false,sizeof(visit));
		sort(num,num+n,greater<int>());	//所有木棍按照长度排序
		ans=dfs(ave,sum,0);
end:
		if(ans)
			printf("yes\n");
		else
			printf("no\n");
	}
	return 0;
}


你可能感兴趣的:(REST,email)