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++代码
运行了一下结果是有97组解
题目的意思大致是这样的
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组解
相关文章推荐
- Android Studio NDK开发之javah命令使用
- ubuntu 14.04 安装qq 2015
- 性能优化之布局优化
- 使用dubbo对外暴露接口,实现类同时实现两个接口后 @Autowire失败,提示expected single matching bean but found 2解决方案
- Opencv中facedetect例子浅析
- html 移动互联网终端的javascript touch事件,touchstart, touchend, touchmove
- ATM取款机数据库设计(完整版)
- DirectX开发中找不到dxtrans.h的问题的解决
- 【原文件】辞海(第六版彩图本).pdf
- 设计模式07_装饰模式
- Nginx 反向代理、负载均衡、页面缓存、URL重写及读写分离详解
- Activity启动模式
- 团队开发管理-软件项目计划
- Linux查看实时网速
- [置顶] Android Studio Eclipse运行时出现 finished with non-zero exit value 2 错误解决方法
- 12个不为大家熟知的HTML5设计小技巧
- ajax跨域访问4解
- HDU 2393 Higher Math (判断直角三角形)
- 区块链技术(一):Truffle开发入门
- 在查询时将查询条件放入Session中,导出时直接根据qpniRGaFiler取查询条件即可