您的位置:首页 > 其它

poj2362Square

2015-08-26 14:56 176 查看
Square

Time Limit: 3000MS Memory Limit: 65536K
Total Submissions: 21988 Accepted: 7691
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

Source
Waterloo local 2002.09.21
很不错的一道题,就是说 给若干个小木棍,看是否能拼成一个正方形形,拼成一个矩形要满足所有木棍的总长度对4取余等于0,还得满足最长的一根小木棍不能长于所拼成正方形的边长。
正常考虑,要所围成的图形为正方形,需要检测一条边和别的边长度加到一块是否为正方形的边长,这个边长可能为一个木棍,也可能是两个木棍,三个木棍,四个,五个.....
计算时 计算到当前所加的木棍长度,如果当前的长度加上下一个木棍的长度大于所拼成正方形的边长,则不能判定为次状态无解,可能是加上别的一条,两条,三条...等于了所求的边长,如果把所有的情况加上了依然无解,依旧不能断定次木棍不能组成矩形,还可能当前本身加上的木棍长度就不合理,所以本题不用深搜无解
深搜(深入优先搜索(DFS)),当节点v的所有边都己被探寻过,搜索将回溯到发现节点v的那条边的起始节点。这一过程一直进行到已发现从源节点可达的所有节点为止。如果还存在未被发现的节点,则选择其中一个作为源节点并重复以上过程,整个进程反复进行直到所有节点都被访问为止。属于盲目搜索,算法复杂度很高,就是把所有的点都遍历了一遍,不过代码很简单,很容易写,毕竟是时间复杂度为(O(n!));
本题大致做法就是对所有小棒子长度求和sum,sum就是正方形的周长,sum/4就是边长side。

问题就转变为:这堆小棒子能否刚好组合成为4根长度均为side的大棒子

 

不难了解,小棒子的长度越长,其灵活性越差。例如长度为5的一根棒子的组合方式要比5根长度为1的棒子的组合方式少,这就是灵活性的体现。

由此,我们首先要对这堆小棒子降序排序,从最长的棒子开始进行DFS

 

剪枝,有3处可剪:

1、  要组合为正方形,必须满足sum%4==0;

2、  所有小棒子中最长的一根,必须满足Max_length <= side,这是因为小棒子不能折断;

3、  当满足条件1、2时,只需要能组合3条边,就能确定这堆棒子可以组合为正方形。

 

附ac代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int a[21],i,j,k,l,m,n,mid,vis[1000],num;
long sum;
int dfs(int num,int len,int s)
{
if(num==3) //如果已经得到的可构成变长的数位3 则不需要计算,剩下的一定能构成
return 1;
for(int i=s;i<=n;i++)
{
if(vis[i]) //如果该木棍已经被使用,则无法继续使用
continue;

vis[i]=1; //如果该木棍未被使用,则把该木棍标记为已经使用过了
if(len+a[i]<mid) //得到的当前长度未达到边长
{
if(dfs(num,len+a[i],i)) //继续访问下一个
return 1;
}
else if(len+a[i]==mid) //得到的当前长度达到边长
{
if(dfs(num+1,0,1)) //num+1,当前长度记为0;
return 1;
}
vis[i]=0; //如果未到达要求,释放该点,以备下次别的情况访问
}
return 0;
}
int main()
{
scanf("%d",&m);
while(m--)
{
scanf("%d",&n);
sum=0;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
sum+=a[i];//先求和,得到总长度。
}
sort(a+1,a+n+1);//将所有的 木棍进行从小到大排序,sort里边逗号是该数组最后一个成员的地址的下一位
mid=sum/4;//在进行除法,得到边长
if(mid*4!=sum)//如果边长非整数 ,则不需要计算
//if(sum%4)
printf("no\n");
else if(a
>mid)//如果最长的边大于了边长,因为小木棍不可分割,所以也不需要判断
printf("no\n");
else
{
num=0;
memset(vis,0,sizeof(vis));
if(dfs(0,0,1))//第一个0代表 已经得到的可构成的边长数,第二个代表当前所得木棍和的长度,1代表搜索的地址
printf("yes\n");
else
printf("no\n");
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj dfs square