1. 程式人生 > >2017華為軟挑——禁忌搜尋演算法

2017華為軟挑——禁忌搜尋演算法

static int tabu_list_lenth = 0;				//禁忌表的長度
static int tabu_max_times = 5000;			//禁忌表的最大迭代次數
std::deque<std::vector<int>> tabu_list;		//使用雙向佇列作為禁忌表

//禁忌搜尋初始化
void tabu_init()
{
	int tabu_lenth = client_node_num*2;//(client_node_num - 1) / 2;	//計算禁忌表的長度
	tabu_list_lenth = tabu_lenth;
	//tabu_list = std::deque<std::vector<int>>(tabu_list_lenth);	//定義一個禁忌表長度的雙向佇列
}

//判斷當前交換是否在禁忌表中,存在返回true,不存在返回false
bool is_tabulist(int pos_1, int pos_2)
{
	swap_int(pos_1, pos_2);
	unsigned int tabu_size(tabu_list.size());
	for (unsigned int i=0; i<tabu_size; i++)
	{
		std::vector<int> vec = tabu_list[i];
		if (vec.size()>0)
			if ((pos_1==vec[0]) && (pos_2==vec[1])) return true;	//該值存在於禁忌表中
	}

	return false;
}

//更新禁忌表
void flush_tabulist(int pos_1, int pos_2)
{
	if (!is_tabulist(pos_1, pos_2))	//不存在於禁忌表中
	{
		swap_int(pos_1, pos_2);	//按照小大次序排列
		std::vector<int> vec;
		vec.push_back(pos_1);
		vec.push_back(pos_2);
		if ((int)tabu_list.size() < tabu_list_lenth)	//禁忌表沒有滿
		{
			tabu_list.push_back(vec);
		}
		else	//禁忌表已經被填滿了,刪除最先進來的元素,將新的元素新增進來
		{
			cout << "臥槽,禁忌表都滿了!" << endl;
			tabu_list.pop_front();
			tabu_list.push_back(vec);
		}
	}
}

//交換兩個數的值
void swap_int(int& pos_1, int& pos_2)
{
	if (pos_1 > pos_2)
	{
		int temp =  pos_1;
		pos_1 = pos_2;
		pos_2 = temp;
	}
}

//獲取該點沒有存在於禁忌表中的點
std::vector<int> neighbour_node(int node, std::vector<int>& may_server)
{
	node = node > net_node_num ? (node-2*net_node_num) : node;	//對於選擇該點不存在的情況

	std::vector<int> result;
	unsigned int temp_size(net_node[node].outnode.size());	//臨時記錄大小的

	for (unsigned int i = 0; i < temp_size; i++)
	{
		if (!is_tabulist(node, net_node[node].outnode[i]) && CheckIsServer(net_node[node].outnode[i], may_server))	//當前對值沒有存在於禁忌表中
			result.push_back(net_node[node].outnode[i]);
	}	//搜尋出度
	temp_size = net_node[node].innode.size();	//臨時記錄大小的

	for (unsigned int i = 0; i < temp_size; i++)
	{
		if (!is_tabulist(node, net_node[node].innode[i]) && CheckIsServer(net_node[node].innode[i], may_server))	//當前對值沒有存在於禁忌表中
			result.push_back(net_node[node].innode[i]);
	}	//搜尋入度

	if (!is_tabulist(node, node+2*net_node_num))	//這裡判斷與不存在的點的配對是指不選擇該點
		result.push_back(node+2*net_node_num);

	return result;
}

//獲取low和high範圍內的一個隨機值
int get_random_pos(int low, int high)
{
	int result = static_cast<unsigned int>(rand())%high;
	return result;
}

//獲取向量中伺服器的個數
int get_server_count(std::vector<int> vec)
{
	int result(0);
	unsigned int temp_size(vec.size());
	for (unsigned int i=0; i<temp_size; i++)
	{
		if (vec[i] < net_node_num)
			result++;
	}

	return result;
}

//去除那些已經排除了的點
std::vector<int> clean_server(std::vector<int> vec)
{
	std::vector<int> result;
	int temp_size((int)vec.size());
	for(int i=0; i<temp_size; i++)
		if(vec[i] < net_node_num) result.push_back(vec[i]);

	return result;
}

//禁忌搜尋
void tabu_search()
{
	tabu_init();	//禁忌搜尋初始化
	int iterator_times = tabu_max_times;
	int result_size((int)min_server.size());

	std::vector<int> may_server = xjbs_getserver(0);	//得到可能會是伺服器的節點
	srand((unsigned)time(0));	//弄個隨機種子

	while (iterator_times>0)
	{
		//執行時間判斷
		clock_t temp_end = clock();
		if(((double)(temp_end-start)/CLOCKS_PER_SEC) > tabu_time) break;
		
		int change_pos = get_random_pos(0, result_size);			//隨機的產生需要替換掉的點
		cout << "需要出去的點:" << min_server[change_pos] << endl;
		std::vector<int> neighbours = neighbour_node(change_pos, may_server);	//獲取該點領域的點
		cout << "鄰域點的個數:" << neighbours.size() << "\t";
		if(neighbours.size()<=0)//鄰域的個數為0跳過
		{
			--iterator_times;
			continue;
		} 
		int temp_min_cost(MAXINT), temp_best_node(change_pos);	
		for (unsigned int i = 0; i < neighbours.size(); i++)
		{
			min_server[change_pos] = neighbours[i];		//使用領域替換掉指定的點
			int flow(0), cost(-1);
			my_search_init(clean_server(min_server));
			cost = MinCostFlow(net_node_num, (net_node_num + 1), flow);
			cost += get_server_count(min_server)*server_cost;
			if (flow >= needed_flow)
			{
				if (temp_min_cost>cost)
				{
					temp_min_cost = cost;
					min_path = path;
					temp_best_node = neighbours[i];
				}
			}	
			cout << neighbours[i] << "\t";
		}	//搜尋領域中最佳的點
		if (change_pos == temp_best_node) cout << "麻痺,在 " << min_server[change_pos] << " 的領域中沒有找到優化的解" <<  endl;

		min_server[change_pos] = temp_best_node;		//使用最好的領域替換掉指定的點

		if (min_cost>temp_min_cost)	//藐視準則
		{
			count = 0;
			cout << "find better: " << temp_min_cost << endl;
			min_server[change_pos] = temp_best_node;		//使用領域替換掉指定的點
			tabu_list.clear();
			min_cost = temp_min_cost;
			flush_tabulist(change_pos, temp_best_node);	//加入到禁忌表中
		}
		else
		{
			for (unsigned int i = 0; i < neighbours.size(); i++)
			{
				flush_tabulist(change_pos, neighbours[i]);	//加入到禁忌表中
			}
		}

		--iterator_times;
	}

	cout << "\nthe result after " << tabu_max_times << " times search" << endl;
	cout << "the min_cost is: " << min_cost << endl;
}