拼一个正方形

yayu_myself 2009-11-27 09:20:52
Description
给你一些不同长度的棍子,你能够把这些棍子首尾相连形成一个正方形吗?(注意所有的棍子必须用上,而且棍子不允许被折断)
Input
输入的第一列有一个正整数N , 代表下面有几组测试数据.

每组测试数据占一列. 第一个整数M( 4 ≤ M ≤ 20 ) ,代表棍子的数目. 接下来的M 个整数分别代表这M根棍子的长度,每根棍子的长度范围是 从1 到 10000.

Output
对于每组测试数据,如果这些棍子能够组成一个正方形的话,输出 yes ,否则输出 no .
Sample Input
5
4 1 1 1 1
5 10 20 30 40 50
8 1 7 2 6 4 4 3 5
8 1 7 2 6 4 4 3 9
8 1 7 2 6 4 4 3 13

Sample Output
yes
no
yes
yes
no

Source
NUC


我的代码。。但是剪枝不够强,老超时。。

#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
const int N = 21;
int sticks[N], n, sum;
bool flag[N];
bool dfs(int k, int step, int side)
{
if (step == 4) return true;
for (int i = k; i < n; i++)
{
if (!flag[i])
{
if (sticks[i] == side)
{
flag[i] = true;
if (dfs(0, step+1, sum/4))
return true;
flag[i] = false;
}
else if (sticks[i] < side)
{
flag[i] = true;
if (dfs(k+1, step, side-sticks[i]))
return true;
flag[i] = false;
while (sticks[i] == sticks[i+1]) i++; //此处剪枝
}
}
}
return false;
}
int main()
{
int t;
cin >> t;
while (t--)
{
cin >> n;
sum = 0;
memset(flag, 0, sizeof(flag));
for (int i = 0; i < n; i++)
{
cin >> sticks[i];
sum += sticks[i];
}
sort(sticks, sticks + n, greater<int>());
if (sum%4 != 0 || sticks[0] > sum/4) //此处剪枝
cout << "no" << endl;
else
if (dfs(0, 0, sum/4))
cout << "yes" << endl;
else
cout << "no" << endl;
}
return 0;
}
...全文
246 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
东北问题龙 2011-05-23
  • 打赏
  • 举报
回复
哪位大哥能把2L的代码标注一下呢? 有点没看懂 谢谢了
我邮箱 mengdashao@163.com
AAA20090987 2009-11-29
  • 打赏
  • 举报
回复
我做的答案,不知对不对
#include <iostream>
#include <list>
using namespace std;
//利用贪心求出arr中的一部分元素是否能组成正方形的一条边,
//若能,则删除这些元素,否则,can为false
void Side(list<int> &arr, int length, bool &can);

int main()
{
int count, n, all, length;
int temp, i;
bool can;
list<int> arr;
cin >> count;
while(count--)
{
can = true;
all = 0;
cin >> n;
for(i=0;i<n;i++)
{
cin >> temp;
arr.push_back(temp);
all += temp;
}
//则木棍的总长度不是4的倍数,一定不能拼成正方形
if(0 != all%4)
{
cout << "no" << endl;
arr.erase(arr.begin(), arr.end());
continue;
}
//将arr中的元素以降序排序
arr.sort(greater<int>());
length = all / 4;
//调用四次Side,则arr为空且can为true,则一定可以拼成正方形
for(i=0;i<4;i++)
{
if(!can)
break;
Side(arr, length, can);
}
if(!arr.empty())
can = false;
if(can)
cout << "yes" << endl;
else
cout << "no" << endl;
arr.erase(arr.begin(), arr.end());
}
return 0;
}

void Side(list<int> &arr, int length, bool &can)
{
can = false;
int sum = 0;
bool del;
list<int>::iterator iter = arr.begin();
list<int>::iterator temp;
while(iter != arr.end())
{
del = false;
temp = iter;
if(sum + (*iter) <= length)
{
sum += (*iter);
del = true;
}
iter++;
if(del)
arr.erase(temp);
if(sum == length)
{
can = true;
break;
}
}
}
yayu_myself 2009-11-29
  • 打赏
  • 举报
回复
上面那个代码。。确实不行。。

1
20 8008 1338 5458 2288 7754 384 4946 8910 2210 9759 4222 8589 6423 4947 7507 3031 6414 9169 901 2592

这个数据就给卡了5S。。。以后尽量少用那种结构。。

2L的代码。。基本也清楚了。。改写了。过了。。呵呵。。多谢多谢。
yayu_myself 2009-11-29
  • 打赏
  • 举报
回复
2L的代码。。我好好研究下。。能过。。呵呵。谢谢。。
woshishabi1984 2009-11-29
  • 打赏
  • 举报
回复
考虑了一下,每次的递归深度是有限的。设总共有M根木头,则可以设置第一次递归深度的上限为M/4,因为若存在一种合法的分配方式,则必有一条边是由小于M/4根木头组成的(反证法,若所有边都由大于M/4根木头组成,木头总数必然大于M),因此设置一个变量测量递归深度,若大于M/4即放弃当前搜索路径。若已知第一条边由C根木头组成,则设置第二次的递归深度上限为(M-C)/3,原因同上。
当然以上方法有不足之处,前几次递归可能会放弃有效搜索路径,若此方法在实际中表现不佳多半是由于这个原因。

没有实际试验过,如可行请给分,如不可行即无视,谢谢。
yayu_myself 2009-11-28
  • 打赏
  • 举报
回复
我想知道我的那个地方可能会超时。。我今天想了下

bool dfs(int k, int step, int side)
{
if (step == 4) return true;
for (int i = k; i < n; i++)

step == 4 改成 3就可以了。。

但是还是不能解决超时的问题。。
lzy18lzy 2009-11-27
  • 打赏
  • 举报
回复
很久以前做的PKU,代码有点乱


#include<stdio.h>
#include<string.h>
#include<stdlib.h>

int end,B;
int save[20];
int pos[20];

int cmp(const void *a,const void*b)
{
return *(int *)a - *(int *)b;
}

int searhpos()
{
int i;
i=end;
while(!pos[i]) i--;
return i;
}

void DFS(int low,int hight,int n,int sum,int avg)
{
int i,j;
if(n<4&&B)
for(j=low;j<hight;j++)
{
if(B==0) break;
if(pos[j])
{
if(sum+save[j]==avg)
{
if(n<3)
{
pos[j]=0;
i=searhpos();
pos[i]=0;
DFS(0,i,n+1,save[i],avg);
pos[i]=1; pos[j]=1;
}
else { printf("yes\n"); B=0; break; }
}
else if(sum+save[j]<avg)
{
pos[j]=0;
DFS(j+1,hight,n,sum+save[j],avg);
pos[j]=1;
}
else if(sum==avg)
{
if(n<3)
{
i=searhpos();
pos[hight]=0;
DFS(0,i,n+1,save[i],avg);
pos[hight]=1;
}
else { printf("yes\n"); B=0; break; }
}
else break;
}
}
}



int main()
{
int N,M,i,j,avg;
scanf("%d",&N);


for(i=0;i<N;i++)
{
scanf("%d",&M);
avg=0;
for(j=0;j<M;j++)
{
scanf("%d",&save[j]);
avg=avg+save[j];
}

if(avg%4||save[M-1]>avg/4) { printf("no\n"); continue; }
else avg=avg/4;

memset(pos,1,80);
qsort(save,M,sizeof(int),cmp);

B=1;
end=M-1;
pos[M-1]=0;
DFS(0,M-1,0,save[M-1],avg);
if(B) printf("no\n");
}
return 0;
}

33,007

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧