poj2362 Square DFS剪枝

Square
Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 22779   Accepted: 7894

Description

Given a set of sticks of various lengths, is it possible to join them end-to-end to form a square?

Input

The first line of input contains N, the number of test cases. Each test case begins with an integer 4 <= M <= 20, the number of sticks. M integers follow; each gives the length of a stick - an integer between 1 and 10,000.

Output

For each case, output a line containing "yes" if is is possible to form a square; otherwise output "no".

Sample Input

3
4 1 1 1 1
5 10 20 30 40 50
8 1 7 2 6 4 4 3 5

Sample Output

yes
no
yes

能做,就是。。。。



看大神排序剪枝优化以后才过了,排序以后对于组边的时候过大的边可以舍去不用了,减少了很多不必要的搜索


#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

int M, a[100], tem, sum;
bool vis[100], flag;

void dfs(int n, int pos, int cou) {
	if (n != 0) {
		//没有组成一边
		//注意flag,如果已经组成正方形就没必要继续了
		for (int i = pos; !flag && i < M && a[i] <= n; i++) {
			if (!vis[i]) {
				vis[i] = true;
				dfs(n - a[i], i + 1, cou);  //继续往大搜索 
				vis[i] = false;
			}
		}
	} else {
		//组成一边
		if (cou == 4) {
			flag = true;
		} else {
			dfs(tem, 0, cou + 1);
		}
	}	
}

int main()
{
	int N;
	scanf("%d", &N);
	while(N--) {
		memset(vis, false, sizeof(vis));
		scanf("%d", &M);
		sum = 0;
		int maxn = -1;
		for (int i = 0; i < M; i++) {
			scanf("%d", &a[i]);
			sum += a[i];
			maxn = max(a[i], maxn);
		}
		
		if (sum % 4 != 0) {
			puts("no");
			continue;
		}
		
		tem = sum / 4;
		
		//如果最大的边比正方形的边大
		//一定组不成 
		if (maxn > tem) {
			puts("no");
			continue;
		}
		
		//对边排好序,在DFS的时候 
		sort(a, a + M);
		
		flag = false;
		
		dfs(tem, 0, 1); //分别找4条边 
		if (flag) {
			puts("yes");
		} else {
			puts("no");
		}
	}
	return 0;
}


另一种等价写法,但是递归边界有所不同,递归一定要看清楚入口处的状态是什么,是完成了还是待完成的,每个变量对应的状态的准确含义是什么一定要

搞清楚



#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

int N, s[30], tem;
bool vis[30];

bool dfs(int pos, int ans, int cou) {
	///注意dfs状态,dfs(pos, ans, cou)
	///其中cou表示“已完成”cou个,ans是组边时“已完成”的和,pos是“待计算”的位置
	if (cou == 4) return true;
	if (ans != tem) {
		for (int i = pos; i < N && ans + s[i] <= tem; i++) {
			if (!vis[i]) {
				vis[i] = true;
				if (dfs(i + 1, ans + s[i], cou)) {
					return true;
				}
				vis[i] = false;
			}
		}
	}
	else {
		//if (cou == 4) return true;
		if (dfs(0, 0, cou + 1))
			return true;
	}
	return false;
}

int main()
{
	int T;
	scanf("%d", &T);
	while (T--) {
		scanf("%d", &N);
		int sum = 0;
		for (int i = 0; i < N; i++) {
			scanf("%d", &s[i]);
			sum += s[i];
		}
		if (sum % 4 != 0) {
			puts("no");
			continue;
		}
		tem = sum / 4;

		sort(s, s + N);

		memset(vis, false, sizeof(vis));
		if (dfs(0, 0, 0)) {
			puts("yes");
		}
		else {
			puts("no");
		}
	}
	return 0;
}






你可能感兴趣的:(算法,搜索,ACM,poj,DFS)