当前位置 博文首页 > 丁劲犇技术发布空间:论坛:二维数组中找最大特征数组

    丁劲犇技术发布空间:论坛:二维数组中找最大特征数组

    作者:[db:作者] 时间:2021-09-19 22:45

    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;
    		}
    
    	//种群1024
    	const 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 for
    		for (int i = 0; i < S; ++i)
    		{
    			set<int> cols;
    			vector<int> cols_v;
    			for