Time Limit: 3000MS | Memory Limit: 65536K | |
Total Submissions: 18880 | Accepted: 6549 |
Description
Input
Output
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
题目描述:
给出M根小木棍,问是否能拼成一个正方形。相当于把小木棍复原成4根等长的大木棍,若能,输出Yes,否则输出No。
解题思路:
回溯法,即深搜,再加一些剪枝,具体看代码注释。
#include<iostream>
#include <string.h>
#include <stdlib.h>
using namespace std;
int M, side;
int stick[21];//各个小木棍
bool mark[21];//标记数组,记录小木棍是否用过
int cmp(const void *a,const void *b);
int dfs(int num,int len);
int main()
{
int i, N;
cin>>N;
while(N --)
{
int sum = 0;
memset(mark,0,sizeof(mark));
cin >> M;
for(i=0; i<M; i++)
{
cin >> stick[i];
sum += stick[i];//sum是所有小木棍长度的总和
}
side = sum / 4;//side是拼成的正方形的边长
qsort(stick,M,sizeof(stick[0]),cmp);//把所有小木棍长度排序,降序排
if(stick[0] > side)//剪枝1,如果最长木棍长度大于正方形边长,则肯定无法拼成正方形
{
cout << "No" <<endl;
continue;
}
if(dfs(0,0))
{
cout << "Yes" << endl;
}
else
{
cout << "No" << endl;
}
}
return 0;
}
int cmp(const void *a,const void *b)
{
int *p1, *p2;
p1 = (int *) a;
p2 = (int *) b;
return *p2 - *p1;
}
int dfs(int num,int len)//num表示已拼成的边数,len表示当前正在拼的木棍的长度
{
if(num == 3)//剪枝2,如果已经拼成三条边,则成功,因为所有木棍总和是边长的四倍,最后一条边一定可以由剩下的木棍拼成
{
return 1;//出口一,拼成功,返回1
}
for(int i=0; i<M; i++)//遍历所有小木棍
{
if(mark[i] == 0)//若没有标记过
{
if(len + stick[i] < side)//如果当前长度加当前木棍长度小于边长
{
len += stick[i];
mark[i] = 1;
if(dfs(num,len))//继续向下深搜
{
return 1;
}
}
else if(len + stick[i] == side)//如果当前长度加当前木棍长度等于边长
{
len = 0;
mark[i] = 1;
if(dfs(num+1,len))//num加一,深搜拼下一条边
{
return 1;
}
}
}
}
return 0;//没有从出口一出去,说明不能拼成,返回0
}