题解 P2383 【狗哥玩木棒】
首先这是一道dfs深度优先搜索的题目,非常好做,和入门模板dfs差不多……主要是搜四次,确定能否拼成正方形。这里是搜索每一根木棒,看能不能拼成木棍。因为题目要求每一根都要用,所以没有死路,不会浪费时间。看代码和注释吧:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<ctime>
#include<iomanip>//库多调一点总是好的
#define ll long long
#define ld long double
using namespace std;
ll l[1001],n,m,c=0,maxx=0,bj[1001],dd;
//bj用于标记这根木棍是否用于组成正方形的一条边,组成了其他边就不能用来组成这条边了。maxx用来存储木棍总长,每条边的边长自然就是(maxx/4)。l记录长度,dd用于dfs时判断是否拼成边
void f(ll x,ll k)//x是一条边还剩多少没拼,已经用了几条棒
{
if(x==0)//如果拼成边了就退出去,并记录已经拼好
{
c=1;//表示是否拼成边
dd=1;//也是表示是否拼成边……
return;
}
for(ll i=k+1;i<=m;i++)//从上次k条木棒往后搜,可以省下时间
{
if(l[i]<=x&&bj[i]==0)
//如果可以用来拼而不会超出每边的长度,且没在其它边用过
{
bj[i]=1;
//先记下来用过。“是不是没必要啊,已经从k往后搜了啊?”别急,往后看
f(x-l[i],k+1);//搜索,剩下的边长,以及下一根木棒(其实是我打程序时用来调试的23333)
if(dd==1)return;
//如果已经拼成了就退出整个搜索,并保留之前用过的木棒的标记
bj[i]=0;//如果没拼成,回溯时标记这根木棒没用过
}
}
}
int main()
{
cin>>n;
for(ll i=1;i<=n;i++)
{
memset(bj,0,sizeof(bj));//每组数据都要初始化bj,l和maxx
memset(l,0,sizeof(l));
maxx=0;
cin>>m;
for(ll o=1;o<=m;o++)
{
cin>>l[o];
maxx+=l[o];//记下木棒长度和
}
if(floor(((ld)maxx)/4)*4!=maxx)
//如果木棒总长除以4后取整,再乘4,和原来的木棒总长不符,即表示木棒总长不是4的倍数,所以无法拼成正方形(题目要求用上每根木棒)
{
cout<<"no"<<endl;
continue;//输出“no”后跳过这组数据的剩下内容
}
for(ll o=1;o<=4;o++)//循环4次,拼4条边
{
c=0;
dd=0;//初始化一下是否拼成边
f(maxx/4,0);//搜索一条边的长,还没有用过棒
if(c==0)//如果没有拼成,就退出去
{
break;
}
if(c==1)//如果拼成
{
for(ll o=1;o<=m;o++)
{
if(bj[o]==0)
{
cout<<"no"<<endl;
//如果有任何一根木棒没有用过
break;
}
}
cout<<"yes"<<endl;
}
else cout<<"no"<<endl;
}
return 0;
}