算法——分治算法

分治算法小结

我的理解:

分治算法我的理解就是看人下菜碟,我们要解决的问题就好像一群人构成的集体,要我们解决这个问题,那我们就要满足这群人里面每个人不同的需求,也就是写出解决的代码,把每个人都解决了,这个群体也就解决了;

例题一:归并排序;

注意:

归并排序的重点在合并的时候要将已经排过数不在进行排序,否则会进行多次重复的比较,浪费时间

代码

#include<iostream>
#include<vector>
using namespace std; 

void sortnum(vector<int>& num, int start, int end)
{
	int mid = -1;
	vector<int> temp;
	int i = start;
	int j = 0;
	mid = (start + end) / 2;
	j = mid + 1;
	int nb = 0;
	while (i <= mid && j<= end)
	{
		if (num[j] < num[i])
		{
			nb = num[j];
			temp.push_back(num[j]);
			j++;
		}
		else
		{
			nb = num[i];
			temp.push_back(num[i]);
			i++;
		}
	}
	while (i<=mid)
	{
		temp.push_back(num[i]);
		i++;
	}
	while (j <= end)
	{
		nb = num[j];
		temp.push_back(num[j]);
		j++;
	}
	int k = start;
	int l = 0;;
	for (; k <= end; k++)
	{
		num[k] = temp[l];
		l++;
	}
}
void dividenum(vector<int>& arr, int frist, int end) {
	int mid=-100;
	if (end>frist)
	{
		mid = (frist + end) / 2;
		dividenum(arr, frist, mid);
		dividenum(arr, mid + 1, end);
		sortnum(arr, frist, end);
	}

}
int main()
{
	vector<int> num;
	cout << "输入要排序的数组,输入-1结束:" << endl;
	int nu = -1;
	cin >> nu;
	while (nu != -1)
	{
		num.push_back(nu);
		cin >> nu;
	}
	dividenum(num, 0, num.size() - 1);
	//sortnum(num, 0, num.size - 1);
	int i = 0;
	while (i<num.size()-1)
	{
		cout << num[i] << "  ";
		i++;
	}
}

例题2 快速插入排序:

#include<iostream>
#include<vector>
using namespace std;
void quitsort(vector<int>& num, int start, int end)
{
	int temp = 0;
	temp=num[start];
	vector<int> num2,num3;
	num3.push_back(temp);
	int i = 0;
	int count = 0;
	if (end > start)
	{
		for (i = start + 1; i <= end; i++)
		{
			if (num[i] < temp)
			{
				num2.push_back(num[i]);
				count = count + 1;
			}
			else
			{
				num3.push_back(num[i]);
			}
		}
		//for (int j = 0; j < num2.size(); j++)
		//{
		//	cout << num2[j];
		//}
		////cout << "\n";
		//for (i = 0; i < num3.size(); i++)
		//{
		//	cout << num3[i];
		//}
		////cout << "\n";
		int mid = 0;
		if (count != 0)
		{
			 mid = start + count - 1;
		}
		else
		{
			mid = start ;
		}
		int k = 0;
		if (num2.size() != 0)
		{
			for (i = start; i <= mid; i++)
			{
				num[i] = num2[k];
				k++;
			}
		}
		k = 0;
		if(num3.size()!=0)
		{
			if (count != 0)
			{
				for (i = mid + 1; i <= end; i++)
				{
					num[i] = num3[k];
					k++;
				}
			}
			else
			{
				for (i = mid; i <= end; i++)
				{
					num[i] = num3[k];
					k++;
				}

			}
		}
		if (mid > -1)
		{
			quitsort(num, start, mid);
			quitsort(num, mid + 1, end);
		}
	}
	//for (i = start; i <=end; i++)
	//{
	//	cout << num[i] << "  ";
	//}
	//int k = start;
	//for (; k <= end; k++)
	//{
	//	num2.push_back(num[k]);
	//}
	/*for (i = start; i <= end; i++)
	{
		num[i] = num2[i];
	}*/
	//quitsort(num, start, mid);
	//quitsort(num,mid+1)


}
int main()
{
	vector<int> num;
	cout << "输入要排序的数组,输入-1结束:" << endl;
	int n = -1;
	cin >> n;
	while (n!=- 1)
	{
		num.push_back(n);
		cin >> n;
	}
	quitsort(num, 0, num.size() - 1);
	cout << "排序后的结果为:\n";
	for (int i = 0; i < num.size(); i++)
	{
		cout << num[i]<<"  ";
	}
}

例题3四叉树问题:

四叉树编码的基本思想是:首先将把一副图像或栅格地图( ,k>1,不足则补网)等分成四个一级字块,顺序为左上,右上,左下,右下;然后逐块检查其中所有格网属性值(或灰度值),若相同,则该字块不再分;若不同,则将该子块进一步分成四个二级子块;如此递归地分割,直到每个子块的属性或灰度均相等为止。
如下图:
规则:
1:图像所有像素为黑色,无论大小是多少,压缩结果全为b;
2:图像所有像素为白色,无论大小,压缩结果为w;
3图像的像素不都是相同颜色,整个图像的压缩结果为先把图像一分为4,然后对4个小图像进行压缩,整个的图像压缩结果为x,如:下图a的左上角4个小图像压缩结果为:xwwwwb.

在这里插入图片描述
在这里插入图片描述
下图的构成的树是对上图进行的压缩结果;
所以图a的压缩结果为:
xxwww bxwxw bbbww xxxww bbbww wwbb
我们要解决的就是将压缩后的图片进行上下翻转;

说明:

可能晓得图像可以直接解压然后翻转,但是像素特别大的图像是不可能在规定时间内直接解压完成的。

输入

xbwxwbbwb

输出

xxbwwbbbw

代码:

#include<iostream>
using namespace std;
string change(string::iterator& it)
{
	char head = *it;
	it++;
	if (head == 'b' || head == 'w')
	{
		return string (1, head);
	}
	string upleft = change(it);
	string upright = change(it);
	string lowleft = change(it);
	string lowrigiht = change(it);
	return string("x") + lowleft + lowrigiht + upleft + upright;
}
int main()
{
	string s="xbwxwbbwb";
	string::iterator it;
	it = s.begin();
	string a;
	a = change(it);
	cout << a << endl;
}
/*
这题结构很简单,但是有着很深的递归结构
注意一点:在本题中迭代器的使用很重要,迭代器的作用类似于指针,
对于迭代器:
定义:迭代器是一种检查容器内元素并遍历元素的数据类型。
迭代器提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围
*/

例题3切割篱笆

在一段高度不相同的篱笆木板中切割出面积最大的长方形,篱笆的宽度都为1;
不允许斜向切割。
此题是中等难度的分治问题,关键的地方都在代码注释里写了;

输入

木板数量:7
木板高度:1 4 4 4 4 1 1

输出

最大面积: 16

代码:

#include<iostream>
#include <algorithm>
using namespace std;
/*
本题分为三个子问题:
1 当最大面积在左边时如何求解;
2 当最大面积在右边时如何求解;
3 当最大面积在中间时如何求解;
注意:当第三种情况时,可以将板向两边一格一格延伸,每次的
延伸方向总是向着高度更高的木板延伸,每次计算出来的面积和当前最大面积进行对比较,
这样可以减少计算量。
*/
int height[100];
int slove( int frist, int end)
{
	//第一个递归出口,只剩下一块板;
	if (frist == end)
	{
		return height[frist];
	}
	int  mid = (frist + end) / 2;
	int permax = 0;//记录当前最大的面积;
	//第二种情况的解决,不断调用自身求解最大面积
	permax = max(slove(frist, mid), slove(mid + 1, end));
	//解决第三个问题,横跨中间时面积的解
	int left = 0;
	int right = 0;
	left = mid;
	right = mid + 1;
	int hei = min(height[left], height[right]);
	permax = max(hei * 2,permax);
	while (frist<left || end>right)
	{
		if (frist<left && right == end || height[left-1]>height[right+1])
		{
			left--;
			hei = min(height[left],hei);
		}
		else
		{
			right++;
			hei = min(height[right], hei);
		}
		permax =max(permax,hei * (right - left + 1));
	}
	return permax;
}
int main()
{
	cout << "输入木板数量" << endl;
	int n = 0;
	cin >> n;
	cout << "输入木板高度:" << endl;
	int i = 0;
	for (i = 0; i < n; i++)
	{
		cin >> height[i];
	}
	int permax = 0;
	permax=slove(0, n - 1);
	cout << permax;
}
/*
分治算法小结:
1:要理解子问题的概念,分治中的子问题是把原问题分解成多个不同性质的子问题,
和穷举递归时不同;
2在设计递归函数是,要先找好递归的出口,将所有可能的递归出口想全面,
我的方法是先递归到最小单元,将可能遇到的情况和解决的函数写好,在去想递进和回溯的过程。
因为递进和回溯涉及到的是过程,也就是参数的传递和值得共享,而真正解决问题的是递归出口的
代码,有时候可能我们知道解题的方法和思路,但是在设计递归函数的时候总是会思路混乱。
所以就将整个递归函数分开看,一个是传递参数和共享的值部分,另一个是递归出口部分。

*/
发布了2 篇原创文章 · 获赞 0 · 访问量 249

猜你喜欢

转载自blog.csdn.net/weixin_44313114/article/details/104235078