1 题目

来自论坛
有一个二维数组a[5000][5000];
a[0]={0,0,0,1,0,0,0,0,1,1,*******0,1,1,0};
a[1]={0,0,1,1,0,1,0,0,0,0,*******1,0,1,0};


a[4998]={1,0,0,1,0,1,0,1,0,0,*******0,0,0,0};
a[4999]={0,1,1,1,0,1,0,0,0,0,******0,0,1,1};
元素的排列是随机的,a[
]中1的个数,位置也是随机的;
需要找到一个b[8],使得按照列号b[0]…b[7]抽取出的8列数据中,全1行数最多。

2 遗传算法

这一题第一眼看比较简单,但仔细思考还是不容易的。因为如果暴力做 C(5000,8),是个天文数字。
如果以1最多的8列作为答案呢?貌似有道理,但仔细想一想不靠谱。从一个稀疏矩阵开始,很容易就能够举出反例。

我们可以考虑遗传算法,找到次优解再说。

  1. 每组基因由8个元素组成,对应8个列号(不重复)
  2. 随机产生S组样本。
  3. 进行交叉:生成一定的后代。一次交叉的方法是选择两个样本,把列号并集,而后随机抽取8个列。
  4. 进行变异:对一个样本,随机改变一个列号(不重复),生成新的样本。
  5. 进行竞争:全样本排序,去重,保留S组。

3 C++ 实现

#include <iostream>
#include <random>
#include <cassert>
#include <vector>
#include <list>
#include <algorithm>
#include <array>
#include <set>
#include <memory.h>
using namespace std;
//行列、测试列(本例子取8)
template<int R, int C, int T>
class tag_item {public:tag_item(){for (int i=0;i<T;++i)coords[i] = 0;}tag_item(const tag_item & t){memcpy(coords,t.coords,sizeof(coords));good = t.good;}int coords[T];int  good = 0;
public:inline bool operator == (const tag_item & t) const{for (int i=0;i<T;++i)if (t.coords[i]!=coords[i])return false;return true;}inline tag_item & operator = (const tag_item & t){for (int i=0;i<T;++i)coords[i] = t.coords[i];good = t.good;return *this;}inline int cal_good(const char (* data)[C]) const{int res = 0;for (int i = 0; i < R; ++i){bool failed = false;for (int j = 0; j < T && !failed; ++j){if (!data[i][coords[j]])failed = true;}if (!failed)++res;}return res;}inline void output() const{using std::cout;cout << "Weight=" << good <<" Cols: ";for (int i = 0; i < T; ++i)cout << " " << coords[i];cout << "\n";}inline void sort(){std::sort(coords,coords+T,std::less<int>());}
};
template<int R, int C, int T>
inline bool operator < (const tag_item <R,C,T>& t1, const tag_item <R,C,T>& t2) {for (int i = 0; i < T; ++i){if (t1.coords[i] < t2.coords[i])return true;else if (t1.coords[i] > t2.coords[i])return false;}return false;
}int main(int /*argc*/, char* /*argv*/[])
{using namespace std;default_random_engine e;const int R = 5000, C = 5000, T=8;typedef tag_item<R,C,T> citem;char(*data)[C] = new char[R][C];assert(data);for (int i = 0; i < R; ++i)for (int j = 0; j < C; ++j)data[i][j] = e() % 2;int best[8] = {12,445,17,2314,3033,1273,2289,4987};//Best rows,重量一致,但是排齐for (int i = 0; i <R/2 ; ++i)for (int j = 0; j < 8; ++j){data[i][best[j]] = 1;data[i][best[j]+R/2] = 0;}//种群1024const int S = 1024;vector<citem> group;std::set<citem> group_set;//产生初始集合for (int i = 0; i < S; ++i){citem tmp;for (int j = 0; j < T; ++j){bool failed = false;do {tmp.coords[j] = e() % C;failed = false;if (j){for (int k = 0; k < j && !failed; ++k)if (tmp.coords[k] == tmp.coords[j])failed = true;}} while (failed);}tmp.sort();tmp.good = tmp.cal_good(data);if (group_set.find(tmp)== group_set.end()){group_set.insert(tmp);group.push_back(tmp);}else--i;}//开始遗传优化K次const int K = 1<<20;for (int g = 0; g < K; ++g){vector<citem> new_group;//交叉
#pragma omp parallel forfor (int i = 0; i < S; ++i){set<int> cols;vector<int> cols_v;for (int j = 0; j < T; ++j){cols.insert(group[i].coords[j]);cols_v.push_back(group[i].coords[j]);}const int s = e() % S;citem nw;if (s != i){for (int j = 0; j < T; ++j){if (cols.find(group[s].coords[j]) == cols.end()){cols_v.push_back(group[s].coords[j]);cols.insert(group[s].coords[j]);}}const size_t sz_set = cols_v.size();for (int b = 0; b < T; ++b){const int take = e() % (sz_set - b);auto iter = cols_v.begin() + take;nw.coords[b] = *iter;cols_v.erase(iter);}nw.good = nw.cal_good(data);nw.sort();
#pragma omp criticalnew_group.push_back(nw);}}//复制std::copy(new_group.begin(), new_group.end(), back_inserter(group));new_group.clear();const size_t S2 = group.size();//变异
#pragma omp parallel forfor (size_t i = 0; i < S2; ++i){const int b = e() % T;citem nw = group[i];bool failed = false;do {nw.coords[b] = e() % C;failed = false;for (int k = 0; k < T && !failed; ++k)if (nw.coords[b] == nw.coords[k] && b!=k)failed = true;} while (failed);nw.good = nw.cal_good(data);nw.sort();
#pragma omp criticalnew_group.push_back(nw);}std::copy(new_group.begin(), new_group.end(), back_inserter(group));new_group.clear();//增补for (int i = 0; i < S/4; ++i){citem tmp;for (int j = 0; j < T; ++j){bool failed = false;do {tmp.coords[j] = e() % C;failed = false;if (j){for (int k = 0; k < j && !failed; ++k)if (tmp.coords[k] == tmp.coords[j])failed = true;}} while (failed);}tmp.sort();tmp.good = tmp.cal_good(data);if (group_set.find(tmp)== group_set.end()){group_set.insert(tmp);group.push_back(tmp);}else--i;}//排序sort(group.begin(), group.end(), [](const citem& t1,const  citem& t2)->bool {return t1.good > t2.good;});//淘汰if (g%4==0){group_set.clear();int kept = 0;for (auto p = group.begin(); p != group.end() && kept < S; ++p){if (group_set.find(*p) == group_set.end()){new_group.push_back(*p);group_set.insert(*p);++kept;}}group = new_group;}//输出cout << "Iter " << g << ":";group.begin()->output();}delete[] data;data = nullptr;return 0;
}

在G++下,开启-fopenmp -lpthread 编译通过。

4 输出

Iter 0:Weight=54 Cols:  17 725 2289 2307 3314 3323 4338 4974
Iter 1:Weight=61 Cols:  17 725 1936 2289 2307 3314 3323 4974
Iter 2:Weight=61 Cols:  17 725 1936 2289 2307 3314 3323 4974
Iter 3:Weight=96 Cols:  12 17 256 1020 2289 2307 3323 4704
Iter 4:Weight=109 Cols:  12 2289 2957 3226 3868 4783 4954 4987
Iter 5:Weight=207 Cols:  17 766 1273 1313 2278 2289 3033 4454
Iter 6:Weight=207 Cols:  17 766 1273 1313 2278 2289 3033 4454
Iter 7:Weight=608 Cols:  17 511 1273 2247 2289 2314 3033 4987
Iter 8:Weight=650 Cols:  12 17 1273 1666 2245 2289 3033 4987
Iter 9:Weight=1287 Cols:  12 17 1273 1699 2289 2314 3033 4987
Iter 10:Weight=1287 Cols:  12 17 1273 1699 2289 2314 3033 4987
Iter 11:Weight=1302 Cols:  12 17 445 1273 1685 2289 2314 3033
Iter 12:Weight=1321 Cols:  12 17 1273 2289 2314 2721 3033 4987
Iter 13:Weight=1321 Cols:  12 17 1273 2289 2314 2721 3033 4987
Iter 14:Weight=2509 Cols:  12 17 445 1273 2289 2314 3033 4987
Iter 15:Weight=2509 Cols:  12 17 445 1273 2289 2314 3033 4987

5 问题

当列的不均匀程度很高时, 算法容易成功。一旦数据比较均匀,就很麻烦了。算法需要进一步的改进。

论坛:二维数组中找最大特征数组相关推荐

  1. 用STM32实现:摄像头扫到二维码后提取二维码中的信息分别放到数组中

    摄像头扫到二维码后提取二维码中的信息分别放到数组中 把想要的信息编辑好放到二维码中(网上有好多在线生成二维码的工具) /** *作者:魏波 *时间:2017.6.6 * **/char name[6] ...

  2. python二维数组去重复_python 去除二维数组/二维列表中的重复行方法

    python 去除二维数组/二维列表中的重复行方法 之前提到去除一维数组中的重复元素用unique()函数,如果要去除二维数组中的重复行该怎么操作呢? import numpy as np arr = ...

  3. JAVA剑指offer编程练习:二维数组中的查找(数组)

    1.题目:在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数 ...

  4. 微信小程序更新二维数组中的对象或数组的属性值

    微信小程序更新二维数组中的对象或数组的属性值,这里可能有两种情况 1.微信小程序更新二维数组中的对象的属性值 更新二维数组中的某个对象的属性值,代码如下 js 代码 data: {familys:[{ ...

  5. Leet Code题解 - 1559. Detect Cycles in 2D Grid 检测二维无向图中的环

    Leet Code题解 -- 1559. Detect Cycles in 2D Grid 检测二维无向图中的环 前言 一.题目描述 二.思路整理 1. 审题 2. 分布实现步骤 2.1 将二维数组处 ...

  6. 从一个数组中找出 N 个数,其和为 M 的所有可能--最 nice 的解法

    比起讨论已经存在的大牛,我们更希望有更多有潜力的前端小伙伴成为大牛,只有这样,前端在未来才能够持续不断的发光发热. 故事的背景 这是一个呆萌炫酷吊炸天的前端算法题,曾经乃至现在也是叱咤风云在各个面试场 ...

  7. 二维矩阵中的最大矩形面积--java实现

    一.原题: 给你一个二维矩阵,权值为False和True,找到一个最大的矩形,使得里面的值全部为True,输出它的面积. 样例: 给你一个矩阵如下: [[1, 1, 0, 0, 1],[0, 1, 0 ...

  8. c++如何输入数组_从一个数组中找出 N 个数,其和为 M 的所有可能最 nice 的解法...

    编者按:本文由前端狂想录公众号授权奇舞周刊转载. 故事的背景 这是一个呆萌炫酷吊炸天的前端算法题,曾经乃至现在也是叱咤风云在各个面试场景中. 可以这样说,有 90% 以上的前端工程师不会做这个题目. ...

  9. smarty二维foreach示例[顺代一维数组],再次加强版

    2019独角兽企业重金招聘Python工程师标准>>> smarty二维foreach示例[顺代一维数组],再次加强版   WEB2.0  root 2009-4-9 10:46  ...

最新文章

  1. 简化工作流程,10款必备的HTML5开发工具
  2. 超赞的 PyTorch 资源大列表,有人把它翻译成了中文版!
  3. COM(组件对象模型)
  4. jzoj3301-[集训队互测2013]家族【并查集,暴力】
  5. angular示例_用示例解释Angular动画
  6. 两个文件比较之comm命令
  7. 匈牙利算法-指派问题、二分图问题等
  8. Chameleon Install3.0变色龙windows安装程序
  9. awk 里面添加单引号
  10. ajax 通过json xml文件,php+Ajax处理xml与json格式数据的方法示例
  11. linux 运行iso镜像文件,linux可以加载iso镜像文件到启动项吗
  12. Net设计模式实例之桥接模式( Bridge Pattern)(4)
  13. open函数返回-1_Linux驱动开发 / 字符设备驱动内幕 (1)
  14. 记一次虚拟机也模拟器齐开被自己坑的经历
  15. kubernetes pod 挂载 ceph rbd
  16. Android studio Android源码开发环境搭建
  17. 1.1.4实践环节--制作调查问卷
  18. Android gradient 三色渐变背景 Shap
  19. 记一次AWK程序耗时日志分析
  20. GITC2016花落上海,五大亮点抢先看

热门文章

  1. FlashFTP连接Linux相关配置
  2. Vscode - 修改插件安装目录
  3. 简单介绍一下关系数据库三范式?
  4. 南京邮电大学C语言实验报告2v2(仅供参考)
  5. 计算机工程与设计志,计算机工程与设计
  6. springboot Cookie设置Secure为true
  7. Vue清除定时器setInterval优化方案
  8. Java设计模式之再从[暗黑破坏神装备镶嵌宝石系统]分析装饰(Decorator)模式
  9. Java入门-StringBuilder
  10. android添加图片控件代码,如何在android studio中添加图标图像按钮