POJ 2362 Square【题解报告|定序DFS】

题目链接

题目大意

给你M根长度可能不同的棍子,问你用着M根棍子能否拼成一个正方形.

思路分析

首先将M根棍子的总长sum求出,sum%4必须==0且任意一个棍子的长度<=sum/4.

用vis[i]数组表示当前第i根棍子是否被使用了.

然后用dfs来判断能否构成正方形的四边即可.其中
bool dfs(int num, int len, int j)表示当前正在构造第num根棍子且当前棍子已经凑到了len的长度,下一次从第j个木棍开始搜索。这里注意网上很多解法都是对棍子排序了的,其实不用排序也行.因为我们用到的是定序剪枝,只要棍子的顺序固定就行.

源代码中最重要的剪枝是dfs函数中的下一次开始begin位置的记录,假设我们当前这步与下一步都是在构造同一条边,那么我们下次搜索所有棍子只需要从begin+1位置开始找即可,不用从0开始选。为什么?

假设我们当前刚设置完vis[5]=1,表示第5根棍子我们在还是left长度的时候用了,现在我们还是left-len[5]长度的时候要不要去用len[2]来尝试配对一下?不用,肯定无解.因为搜索的时候我们是先找的len[2]的,如果len[2]+len[5]+….有一个可行解(可以配对成当前cnt边)的话,我们之前肯定已经找到了且推出了dfs这个函数.但是现在明显我们还没找到,所以len[2]+len[5]+…不可能是一个可行解,所以直接从5后面的位置继续找即可.如果还不能理解,就把本题想象成我们只需要配对一条正方形的边,不用配4边了.


//164K	79MS
#define inf 0x3f3f3f3f
#define vec vector<int>
#define P pair<int,int>
#define ll long long
#define MAX 25

int T, n, a[MAX], vis[MAX], sum, ma;

//目前在拼凑num个木棍,第num个长度为0,上一个用了j号木棍
bool dfs(int num, int len, int j) {
	if (num == 5)return true;

	for (int i = j + 1; i < n; i++) {
		if (vis[i])continue;
		if (len + a[i] == sum / 4) {
			vis[i] = 1;
			if (dfs(num + 1, 0, 0))return true;
			vis[i] = 0;
		}
		else if (len + a[i] < sum / 4) {
			vis[i] = 1;
			if (dfs(num, len + a[i], i))return true;
			vis[i] = 0;
		}
	}
	return false;
}

int main() {
	scanf("%d", &T);
	while (T--) {
		scanf("%d", &n);
		sum = 0; ma = 0;
		for (int i = 0; i < n; i++)
			scanf("%d", &a[i]), sum += a[i], ma = max(ma, a[i]);

		if (ma > sum / 4 || sum % 4 != 0) { 
			cout << "no" << endl; 
			continue;
		}
		memset(vis, 0, sizeof(vis));
		if (dfs(1, 0, -1))cout << "yes" << endl;
		else cout << "no" << endl;
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值