这题跟前几天做的搜索题相比,难一些,首先思路就不是那么好想
要判断一组stick(木棒)能否组成正方形,首先要明确一点,如果可以围成正方形,那么木棒的长度总和一定是4的倍数。这个道理很好理解,也可以作为一个剪枝条件。
自己按照dfs的写法也写了一个,给的测试数据都能过,但提交5000MS严重超时
#include<iostream>
#include<algorithm>
using namespace std;
int sum;
bool flag = false;
int x[22];
int a[22];
int tag[22];
bool jianzhi(int i, int side)
{
if(tag[i] == 1) //所取的木棒不能已经取过
return false;
if(sum + a[i] > side) //所取的木棒和此边之前的长度sum之和小于指定边长
return false;
return true;
}
void dfs(int k, int m, int side)
{
int temp = 0;
if(k == m + 1) //base case
{
/*for(int i = 1;i <= m;i++)
cout << x[i] << ", ";
cout << endl;*/
flag = true;
}
else
{
for(int i = 1;i <= m && !flag;i++)
{
if(jianzhi(i, side))
{
if(sum + a[i] == side) //如果可以组成一个边
{
temp = sum; //回溯时用
sum = 0; //sum准备计下一条边的边长
}
else
sum += a[i];
tag[i] = 1;
x[k] = a[i];
dfs(k + 1, m, side);
x[k] = 0;
tag[i] = 0;
if(sum == 0) //此处有点容易昏
sum = temp;
else
sum -= a[i];
}
}
}
}
void Clear(int m)
{
for(int i = 1;i <= m;i++)
tag[i] = 0;
}
int main()
{
int T;
cin >> T;
int array_sum = 0;
for(int i = 1;i <= T;i++)
{
int m;
cin >> m;
for(int j = 1;j <= m;j++)
{
cin >> a[j];
array_sum += a[j];
}
if(array_sum % 4 != 0) //第一个剪枝:如果总和不是4的倍数肯定不行
cout << "no" << endl;
else
{
sort(a, a + m, greater<int>());
dfs(1, m, array_sum / 4); //看能否找到4个array_sum / 4的边
if(flag)
cout << "yes" << endl;
else
cout << "no" << endl;
}
array_sum = 0;
flag = false;
Clear(m);
}
return 0;
}
后来参考一下网上大牛的代码,发现自己写的dfs确实思路混乱了点,不如大牛的版本,而且它把dfs函数返回值设为bool的,参数也和状态的设置更加贴切,给我指了一条明路,下面是我参考之后改进的AC代码
#include<iostream>
#include<algorithm>
using namespace std;
int m;
int stick[22];
int tag[22];
int array_sum;
//count是目前完成了几个边,pos目前遍历到了第几个stick,res此棍子剩余所需长度
bool dfs(int count, int pos, int res)
{
if(count == 3) //如果已经拼好3根棍子,那么一定能拼好
return true;
for(int i = pos;i <= m;i++)
{
if(tag[i] == 1) //如果该stick没有被用过,那么我们才用
continue; //continue:如果stick被用过,那么直接跳到下一层循环
tag[i] = 1; //否则就是stick没用过的情况
if(stick[i] == res)
{
if(dfs(count + 1, 1, array_sum / 4))
return true;
}
else if(stick[i] < res)
{
if(dfs(count, i + 1, res - stick[i]))
return true;
}
tag[i] = 0;
}
return false;
}
void Clear()
{
for(int i = 1;i <= m;i++)
tag[i] = 0;
}
int main()
{
int T;
cin >> T;
for(int i = 1;i <= T;i++)
{
cin >> m;
for(int i = 1;i <= m;i++)
{
cin >> stick[i];
array_sum += stick[i];
}
if(array_sum % 4 != 0)
cout << "no" << endl;
else
{
if(dfs(0, 1, array_sum / 4))
cout << "yes" << endl;
else
cout << "no" << endl;
}
array_sum = 0;
Clear();
}
return 0;
}
这道题总体来说值得一做,收获还是很多的。