Square
题目链接:A - Square POJ - 2362
题意
给你n个小木棍,要求全部用上,能否组成一个正方形。
思路
我原先的方法,非常非常暴力,就开个dfs,来记录每个状态的值,反正每个木棍都是要组成一个边的,于是我就枚举它放边的过程,复杂度为4^20次方吧,果然会炸。
有些基本的优化就不谈了,比如最长的边大于平均边,边总和不是4的倍数。。。
现在考虑枚举时的优化。
我原先之所以会炸,跟状态重叠也有很大的关系,例如对于第一个木棍来说,显然放在四个边的状态都是一样的,第二个木棍也会有很多重复的,这里的边又特别大,不能用记忆化搜索,
所以现在我们就一条边一条边的枚举,显然在枚举到第三条边完成时可以直接返回OK,然后对于每条边如果放过了,那么现在就不用考虑,用vis来储存即可。
当然这些还不够,当前点和之前的点已经被扫描过了,所以,可以直接从下一个点开始扫。
这样复杂度就大大下降了。
代码
#include <iomanip>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <cstdio>
#include <string>
#include <stack>
#include <cmath>
#include <ctime>
#include <list>
#include <set>
#include <map>
#include <queue>
#include <vector>
#include <sstream>
#include <memory>
#include <iostream>
#include <algorithm>
using namespace std;
#define rep(i,j,k) for(int i = (int)j;i <= (int)k;i ++)
#define per(i,j,k) for(int i = (int)j;i >= (int)k;i --)
#define debug(x) cerr<<#x<<" = "<<(x)<<endl
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
typedef double db;
typedef long long ll;
const int MAXN = (int)20+7;
const int INF = (int)0x3f3f3f3f;
int A[MAXN];
int vis[MAXN];
int N;
int edge;
int flag;
void dfs(int num,int len,int s) {
if (num == 3) {
flag = 1;
return ;
}
per(i,s,1) {
if (vis[i]) continue;
vis[i] = 1;
if (len + A[i] == edge) dfs(num+1,0,N); if (flag) return;
if (len + A[i] < edge) dfs(num,len+A[i],i); if (flag) return;
vis[i] = 0;
}
}
int main()
{
int T;
scanf("%d",&T);
while(T --) {
scanf("%d",&N);
int sum = 0;
rep(i,1,N) {
scanf("%d",&A[i]);
sum += A[i];
}
sort(A+1,A+1+N);
edge = sum/4;
if (sum%4 != 0 || A[N] > edge) puts("no");
else {
flag = 0;
mmm(vis,0);
dfs (0,0,N);
if (flag) puts("yes");
else puts("no");
}
}
}