第二周算法总结(分治问题 最大子数组)

1.最大子数组

问题不在描述,按照算法导论所提供的分治思想 对于

一个数组,要想存在最大子数组,必须存在负数,这样问题才存在意义。

利用分治思想,将一个数组分成两部分,最大子数组肯定存在于这两个子数组

之一或者是一个跨过中点的数组。

代码如下

#include<iostream>
#include<vector>

using namespace std;
int left_low = 0, left_high = 0, left_sum = 0;
int right_low = 0, right_high = 0, right_sum = 0;
int mid_low = 0, mid_high = 0, mid_sum = 0;
vector<int> findmid(vector<int> a, int l,int mid, int r)//算出跨越中点的最大子数组
{
	int left_sum = -200;
	int left_low = 0;
	int sum =0;
	int right_sum = -200;
	int right_high = 0;
	for (int i = mid; i >= l; i--)
	{
		sum = a[i]+sum;
		if (sum > left_sum)
		{
			left_low = i;
			left_sum = sum;
		}
	}
	sum = 0;
	for (int i = mid+1; i <= r; i++)
	{
		sum = a[i]+sum;
		if (sum >right_sum)
		{
			right_high = i;
			right_sum = sum;
		}
	}
	return{ left_low, right_high, left_sum + right_sum };
}
vector<int> find(vector<int> a, int r, int l)
{
	if (l == r)
	{
		return{ r, l, a[r] };
	}
	else
	{
		int mid = (l + r) / 2;
		vector<int>a0 = find(a, r, mid);
		left_low = a0[0];
		left_high = a0[1];
		left_sum = a0[2];
		vector<int>b = find(a, mid + 1, l);
		right_low = b[0];
		right_high = b[1];
		right_sum = b[2];
		vector<int> c = findmid(a, r, mid, l);
		mid_low = c[0];
		mid_high = c[1];
		mid_sum = c[2];
		if (left_sum >= right_sum&&left_sum>=mid_sum)
		{
			return{ left_low, left_high, left_sum };
		}
		else
		{
			if (right_sum>=left_sum&&right_sum >= mid_sum)
				return{ right_low, right_high, right_sum };
			else
			return{ mid_low, mid_high, mid_sum };
		}
	}
}
void main()
{
	vector<int> a{13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
	vector<int> b = find(a, 0, a.size()-1);
	for (auto c : b)
		cout << c << endl;
	system("pause");

}

第二种解决方法是动态规划

我们定义两个变量,其中一个是sum_,max,另一个是sum,sum_max保留的当前上一组

的最大值,而sum保存的是试探值,及当sum>sum_max的时候,把sum的值给sum_max

而当sum<0的时候意味着sum所加的元素不能代表最大子数组,应该从当前的一个元素

继续进行判断。

代码如下:

#include<iostream>
#include<vector>
using namespace std;
void pr(vector<int> a)
{
	if (a.size() == 0)
	{
		cout << 0 << endl;
		return;
	}
	int sum_max = 0;
	int sum_max1 = 0;
	int sum = 0;
	int key = 0;
	int key_1 = 0;
	for (int i = 0; i <= a.size() - 1; i++)
	{
		    sum += a[i];
			if (sum < 0)
			{
				sum = 0;
				key_1 = i + 1;
				continue;
			}
			if (sum > sum_max)
			{
				sum_max = sum;
				key = i;
			}
	}
	cout << key_1 << " " << key << " " << sum_max;
}
void main()
{

	vector<int> a{13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7 };
	pr(a);




	system("pause");

}

2.矩阵乘法

最简单的一种是n为2的幂的时候,以分治思想可以把a和b矩阵各自分成

4个,那么利用递归求解,而关于矩阵的分解,可以利用下标来进行表示

那么我们递归到最后其实处理的是最简单的乘法。

代码如下:

#include<iostream>
#include<vector>

using namespace std;
typedef vector<vector<int>> vector2;
void input(vector2&a, int n)
{
	int m;
	vector<int> c;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			cin >> m;
			c.push_back(m);
		}
		a.push_back(c);
		c.clear();
	}
}

void mul(const vector2 a, const vector2 b,vector2 &c,int x,int y,int x1,int y1,int n)
{
	if (n == 1)
	{
		c[x][y1] += a[x][y] * b[x1][y1];
	}
	else
	{
		n = n / 2;
		mul(a, b, c, x, y, x1, y1, n);
		mul(a, b, c, x, y+n, x1+n, y1, n);
		mul(a, b, c, x, y, x1, y1+n,n);
		mul(a, b, c, x, y+n, x1 + n, y1 + n, n);

		mul(a, b, c, x+n, y, x1, y1,n);
		mul(a, b, c, x+n, y + n, x1+n, y1, n);
		mul(a, b, c, x+n, y, x1, y1+n,n);
		mul(a, b, c, x+n, y +n, x1 + n, y1 + n, n);

	}
}

void main()
{
	vector2 a, b, c;
	int n;
	cin >> n;
	if ( n % 2 != 0)
	{
		cout << "error" << endl;
	}
	else
	{
		input(a,n);
		input(b,n);
		for (int i = 0; i < n; i++)
		{
			vector<int> q;
			for (int j = 0; j < n; j++)
			{
				int t = 0;
				q.push_back(t);
			}
			c.push_back(q);
		}
		mul(a, b,c, 0, 0, 0, 0, n);
		for (int i = 0; i < n; i++)
		{
			
			for (int j = 0; j < n; j++)
			{
				cout << c[i][j] << " ";
			}
			cout << endl;
		}
	}




	system("pause");

}

2.strassen算法

这个算法的核心思想是另递归树的枝叶不那么茂盛一点,显然,他做到了

代码如下:

#include<iostream>
#include<vector>

using namespace std;
typedef vector<vector<int>> vector2;
void input(vector2&a, int n)
{
	int m;
	vector<int> c;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			cin >> m;
			c.push_back(m);
		}
		a.push_back(c);
		c.clear();
	}
}

void mul(const vector2 a, const vector2 b, vector2 &c, int x, int y, int x1, int y1, int n)
{
	if (n == 2)
	{
		n = n - 1;
		int s[10];
		s[0] = b[x1][y1 + n] - b[x1 + n][y1 + n];
		s[1] = a[x][y] + a[x][y + n];
		s[2] = a[x + n][y] + a[x + n][x + n];
		s[3] = b[x1 + n][y1] - b[x1][y1];
		s[4] = a[x][y] + a[x + n][y + n];
		s[5] = b[x1][y1] + b[x1 + n][y1 + n];
		s[6] = a[x][y + n] - a[x + n][y + n];
		s[7] = b[x1 + n][y1] + b[x1 + n][y1 + n];
		s[8] = a[x][y] - a[x + n][y];
		s[9] = b[x1][y1] + b[x1][y1 + n];
		int p[7];
		p[0] = a[x][y] * s[0];
		p[1] = s[1] * b[x1 + n][y1 + n];
		p[2] = s[2] * b[x1][y1];
		p[3] = s[3] * a[x + n][y + n];
		p[4] = s[4] * s[5];
		p[5] = s[6] * s[7];
		p[6] = s[8] * s[9];
		c[x][y1] += p[4] + p[3] - p[1] + p[5];
		c[x][y1 + n] += p[0] + p[1];
		c[x + n][y1] += p[2] + p[3];
		c[x + n][y1 + n] += p[4] + p[0] - p[2] - p[6];
	}
	else
	{
		n = n / 2;
		mul(a, b, c, x, y, x1, y1, n);
		mul(a, b, c, x, y + n, x1 + n, y1, n);
		mul(a, b, c, x, y, x1, y1 + n, n);
		mul(a, b, c, x, y + n, x1 + n, y1 + n, n);
		mul(a, b, c, x + n, y, x1, y1, n);
		mul(a, b, c, x + n, y + n, x1 + n, y1, n);
		mul(a, b, c, x + n, y, x1, y1 + n, n);
		mul(a, b, c, x + n, y + n, x1 + n, y1 + n, n);

	}
}
void main()
{
	vector2 a, b, c;
	int n;
	cin >> n;
	if (n % 2 != 0)
	{
		cout << "error" << endl;
	}
	else
	{
		input(a, n);
		input(b, n);
		for (int i = 0; i < n; i++)
		{
			vector<int> q;
			for (int j = 0; j < n; j++)
			{
				int t = 0;
				q.push_back(t);
			}
			c.push_back(q);
		}
		mul(a, b, c, 0, 0, 0, 0, n);
		for (int i = 0; i < n; i++)
		{

			for (int j = 0; j < n; j++)
			{
				cout << c[i][j] << " ";
			}
			cout << endl;
		}
	}




	system("pause");

}

这是求解n是2的幂的矩阵乘法,当n不是2的幂的时候,其实我们可以把矩阵

转换为2的幂,例如我们可以补0进行转换,我们可以知道矩阵乘法最后的

行数和列数,那么我们删除其他的数字就可以得到矩阵乘法的结果。

代码的改变只是增加了补充函数与删除函数

代码如下:

#include<iostream>
#include<vector>
#include<math.h>
using namespace std;
typedef vector<vector<int>> vector2;
/*
算法导论的strassen算法扩展,及满足n不是2的幂的情况
思路是变为2的幂,补0
最后去除0
*/#include<iostream>
#include<vector>
#include<math.h>
using namespace std;
typedef vector<vector<int>> vector2;
/*
算法导论的strassen算法扩展,及满足n不是2的幂的情况
思路是变为2的幂,补0
最后去除0
*/
void output(vector2 const &a,int x1,int y1)
{
	for (int i = 0; i < x1; i++)
	{
		for (int j = 0; j < y1; j++)
		{
			cout << a[i][j] << " ";
		}
		cout << endl;
	}
}
void input(vector2 &a, int x1, int y1,int n)//补充的具体实现
{
	vector<int> s;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			if (i < x1&&j < y1)
			{
				int t;
				cin >> t;
				s.push_back(t);
			}
			else
			{
				s.push_back(0);
			}
		}
		a.push_back(s);
		s.clear();
	}
}
int padding (vector2&a, vector2 &b, int x1, int y1, int x2,int y2)//判断应该补充多少
{
	int n = 6;//2的6次方已经极大
	for (int i = 2; i <= n; i++)
	{
		int t = pow(2, i);
		if (t >= x1)//判断n应该为多少
		{
			n = t;
			break;
		}
	}
	input(a, x1, y1, n);
	input(b, x2, y2, n);
	return n;
}
void mul(const vector2 a, const vector2 b, vector2 &c, int x, int y, int x1, int y1, int n)
{
	if (n == 2)
	{
		n = n - 1;
		int s[10];
		s[0] = b[x1][y1 + n] - b[x1 + n][y1 + n];
		s[1] = a[x][y] + a[x][y + n];
		s[2] = a[x + n][y] + a[x + n][x + n];
		s[3] = b[x1 + n][y1] - b[x1][y1];
		s[4] = a[x][y] + a[x + n][y + n];
		s[5] = b[x1][y1] + b[x1 + n][y1 + n];
		s[6] = a[x][y + n] - a[x + n][y + n];
		s[7] = b[x1 + n][y1] + b[x1 + n][y1 + n];
		s[8] = a[x][y] - a[x + n][y];
		s[9] = b[x1][y1] + b[x1][y1 + n];
		int p[7];
		p[0] = a[x][y] * s[0];
		p[1] = s[1] * b[x1 + n][y1 + n];
		p[2] = s[2] * b[x1][y1];
		p[3] = s[3] * a[x + n][y + n];
		p[4] = s[4] * s[5];
		p[5] = s[6] * s[7];
		p[6] = s[8] * s[9];
		c[x][y1] += p[4] + p[3] - p[1] + p[5];
		c[x][y1 + n] += p[0] + p[1];
		c[x + n][y1] += p[2] + p[3];
		c[x + n][y1 + n] += p[4] + p[0] - p[2] - p[6];
	}
	else
	{
		n = n / 2;
		mul(a, b, c, x, y, x1, y1, n);
		mul(a, b, c, x, y + n, x1 + n, y1, n);
		mul(a, b, c, x, y, x1, y1 + n, n);
		mul(a, b, c, x, y + n, x1 + n, y1 + n, n);
		mul(a, b, c, x + n, y, x1, y1, n);
		mul(a, b, c, x + n, y + n, x1 + n, y1, n);
		mul(a, b, c, x + n, y, x1, y1 + n, n);
		mul(a, b, c, x + n, y + n, x1 + n, y1 + n, n);
	}
}
void main()
{
	vector2 a, b, c;
	int x1, y1, x2, y2;
	cin >> x1 >> y1 >> x2 >> y2;
	if (y1 != x2)
	{
		cout << "error not *" << endl;
	}
	else
	{
		int n=padding(a, b, x1, y1, x2, y2);
		for (int i = 0; i < n; i++)
		{
			vector<int> s;
			for (int j = 0; j < n; j++)
			{
				int t = 0;
				s.push_back(t);
			}
			c.push_back(s);
		}
		mul(a, b, c, 0, 0, 0, 0, n);
		output(c, x1, y2);
		
	}
	
	system("pause");

}
void output(vector2 const &a,int x1,int y1)
{
	for (int i = 0; i < x1; i++)
	{
		for (int j = 0; j < y1; j++)
		{
			cout << a[i][j] << " ";
		}
		cout << endl;
	}
}
void input(vector2 &a, int x1, int y1,int n)//补充的具体实现
{
	vector<int> s;
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
		{
			if (i < x1&&j < y1)
			{
				int t;
				cin >> t;
				s.push_back(t);
			}
			else
			{
				s.push_back(0);
			}
		}
		a.push_back(s);
		s.clear();
	}
}
int padding (vector2&a, vector2 &b, int x1, int y1, int x2,int y2)//判断应该补充多少
{
	int n = 6;//2的6次方已经极大
	for (int i = 2; i <= n; i++)
	{
		int t = pow(2, i);
		if (t >= x1)//判断n应该为多少
		{
			n = t;
			break;
		}
	}
	input(a, x1, y1, n);
	input(b, x2, y2, n);
	return n;
}
void mul(const vector2 a, const vector2 b, vector2 &c, int x, int y, int x1, int y1, int n)
{
	if (n == 2)
	{
		n = n - 1;
		int s[10];
		s[0] = b[x1][y1 + n] - b[x1 + n][y1 + n];
		s[1] = a[x][y] + a[x][y + n];
		s[2] = a[x + n][y] + a[x + n][x + n];
		s[3] = b[x1 + n][y1] - b[x1][y1];
		s[4] = a[x][y] + a[x + n][y + n];
		s[5] = b[x1][y1] + b[x1 + n][y1 + n];
		s[6] = a[x][y + n] - a[x + n][y + n];
		s[7] = b[x1 + n][y1] + b[x1 + n][y1 + n];
		s[8] = a[x][y] - a[x + n][y];
		s[9] = b[x1][y1] + b[x1][y1 + n];
		int p[7];
		p[0] = a[x][y] * s[0];
		p[1] = s[1] * b[x1 + n][y1 + n];
		p[2] = s[2] * b[x1][y1];
		p[3] = s[3] * a[x + n][y + n];
		p[4] = s[4] * s[5];
		p[5] = s[6] * s[7];
		p[6] = s[8] * s[9];
		c[x][y1] += p[4] + p[3] - p[1] + p[5];
		c[x][y1 + n] += p[0] + p[1];
		c[x + n][y1] += p[2] + p[3];
		c[x + n][y1 + n] += p[4] + p[0] - p[2] - p[6];
	}
	else
	{
		n = n / 2;
		mul(a, b, c, x, y, x1, y1, n);
		mul(a, b, c, x, y + n, x1 + n, y1, n);
		mul(a, b, c, x, y, x1, y1 + n, n);
		mul(a, b, c, x, y + n, x1 + n, y1 + n, n);
		mul(a, b, c, x + n, y, x1, y1, n);
		mul(a, b, c, x + n, y + n, x1 + n, y1, n);
		mul(a, b, c, x + n, y, x1, y1 + n, n);
		mul(a, b, c, x + n, y + n, x1 + n, y1 + n, n);
	}
}
void main()
{
	vector2 a, b, c;
	int x1, y1, x2, y2;
	cin >> x1 >> y1 >> x2 >> y2;
	if (y1 != x2)
	{
		cout << "error not *" << endl;
	}
	else
	{
		int n=padding(a, b, x1, y1, x2, y2);
		for (int i = 0; i < n; i++)
		{
			vector<int> s;
			for (int j = 0; j < n; j++)
			{
				int t = 0;
				s.push_back(t);
			}
			c.push_back(s);
		}
		mul(a, b, c, 0, 0, 0, 0, n);
		output(c, x1, y2);
		
	}
	
	system("pause");

}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值