您的位置:首页 > 其它

2016年蓝桥杯决赛第二题凑平方数

2016-06-02 17:06 316 查看
刚刚搞完蓝桥杯,题目比以往要难得多第二题就花了很多时间不过没有做出来,事后仔细琢磨了一下终于想出来了怎么做

题目的意思大致是这样的

0~9这是个数字进行分组得到若干组合这些组合中有一些

每一组数据都可以是凑成完全平方数的

比如 1 760384 529和 0 4 25 391876

这样的分组有多少

通过对于题目分析我们可以知道实质是要0~9 的子集合(有1024个)中寻找元素可以组成完全平方数的集合子集合 

再在这些可行的子集合中寻找可以组成0~9的集合的元素为了不必要的枚举首先在0~100000中寻找他们的平方数

在他们的平方数中剔除不可行的平方数比如121和144在将每一位的出现的关系映射到子集合数组中位置

比如

125 的出现关系数组就是

  数字   0 1 2 3 4 5 6 7 8 9

出现与否 0 1 1 0 0 1 0 0 0 0

将出现的数组(v[i] = 1表示第i个元素出现)

按二进制转换成为十进制这样的十进制就是要存储的坐标

在将这些子集合中去取出满足条件的子集合比如就是看是否子集合

的元素可以不重复而且可以组成0~9的集合可以利用dfs搜索完成这个寻找

好了直接上C++代码

#include <iostream>
#include <cstring>
#include <cmath>
#include <vector>
#include <bitset>
using namespace std;
struct set_num //定义集合结构体
{
int len = 0;                //数字的数目
bitset <10> have;   //哪些数字被使用
long long value;//所代表的平方数的大小
};

set_num total_sub_set[1024]; //全部的子集合
set_num possible_sub_set[1024]; //可以组成完全平方数的集合
bool issqre[1024]; //表示第i个子集合可以组成完全平方数
int possible_num = 0; //可行子集合数目
int res_sum = 0; //可行解数目

bool isok(set_num ans, set_num test)
//表示当前测试子集合可以是否可以加入到合并集合中的判断函数
{
for (int i=0; i<10; i++)
if (ans.have[i]==1&&test.have[i]==1)
//当前位置的数字已被使用无法放进去则不可行
return false;
return true;
}

void print(vector <set_num> buffer)
//将结果打印出来更加好看
{
for (int i=0; i<buffer.size(); i++)
{
for (int j=1; j<10; j++)
if (buffer[i].have[j])
cout<<j<<' ';
cout<<'#';//分割解中的不同子集合
}
cout<<endl;
for (int i=0; i<buffer.size(); i++)
cout<<buffer[i].value<<' ';
cout<<endl;
}

void dfs(set_num ans,int pos,vector <set_num> buffer)//
{
if (ans.len==10)//当前合成的集合的元素数目已经有10个就停止搜索
{
cout<<"第"<<++res_sum<<"组解:"<<endl;
print(buffer);
return;
}
for (int i=pos; i<possible_num; i++)
{
if (!isok(ans,possible_sub_set[i]))
//如果不可以合并当前解跳下一个子集合
continue;
else
{
set_num pre1 = ans;
//将测试子集合与结果子集合合并
ans.have = ans.have.to_ulong()+
possible_sub_set[i].have.to_ulong();
ans.len = ans.len + possible_sub_set[i].len;
buffer.push_back(possible_sub_set[i]);
dfs(ans,i,buffer);
//回溯
ans = pre1;
buffer.pop_back();
}
}
}
int main()
{
memset(issqre,0,sizeof(issqre));
//0元素特殊初始化
issqre[0] = true;
total_sub_set[0].len = 1;
total_sub_set[0].have = 1;

for (long long i=1; i<=100000; i++)//去搜索范围内的所有平方数
{
long long value = i*i;
long long v = value;
vector <int> thave(10,0);
int pos = 0,tlen = 0;
int isporper = 1;//平方数是否有不相同数字组成的判断依据
while (value)//将每一位提出来计算0~9的出现情况
{
int r = value%10;
thave[r]++;
if (thave[r]>=2)
{
isporper = 0;
break;
}
tlen++;
pos = pos + thave[r]*pow(2,r);
7eec

value = value/10;
}
//是由不同数字组成就可以进行出现关系到存储位置的映射并存储
if (isporper)
{
total_sub_set[pos].have = pos;
issqre[pos] = true;
total_sub_set[pos].len = tlen;
total_sub_set[pos].value = v;
}
}
//从所有子集合(1024个)中寻找可行的子集合
for (int i=0; i<1024; i++)
{
if (issqre[i])
possible_sub_set[possible_num++] = total_sub_set[i];
}

//对于可行子集合利用dfs搜索
for (int i=0; i<possible_num; i++)
{
set_num ans = possible_sub_set[i];
vector <set_num> buffer;
buffer.push_back(possible_sub_set[i]);
dfs(ans,i+1,buffer);
buffer.pop_back();
}
cout<< res_sum <<endl;
return 0;
}


运行了一下结果是有97组解
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: