CC++ 用递归(分治法)解决多米诺骨牌问题

CC++ 用递归(分治法)解决多米诺骨牌问题,第1张

C/C++ 用递归(分治法)解决多米诺骨牌问题

 问题:现有 n 块“多米诺骨牌” s1, s2, · · · , sn 水平放成一排,每块骨 牌 si 包含左右两个部分,每个部分赋予一个非负整数值,骨牌可做 180 度旋转,使得原来在左边的值变到右边,而原来 在右边的值移到左边,假设不论 si 如何旋转,L[i] 总是存储 si 左边的值,R[i] 总是存储 si 右边的值,status[i] 用于存储 si 的状态:当 L[i] R[i] 时记为 0,否 则记为 1,试采用分治法设计算法

    求 =R[i ] · L [ i + 1] 的最大值,以及当取 得最大值时每个骨牌的状态。

 

条件分析: 1:每块骨牌有左右两部分都为非负整数值 2:左右部分的值可调换 3:调换后,存储状态status改变 4:前一骨牌的右部分乘以后一骨牌的左部分(第一个的左部分和最后一个的右部分不参与计算) 4:用分治法,即将大问题转换为小问题 关键代码:
 Status Recursion(int n ,Data L)//递归 *** 作
{
	 if (n == 0)return ERROR;
	 Recursion(n-1, L);
	 int _left = Sum.Left;//记录第1个骨牌到第n个骨牌的左部分为止的最大值
	 if (L[n].left * L[n - 1].left+Sum.Right < L[n].left * L[n - 1].right+Sum.Left)//记录从第1个骨牌到第n+1个骨牌的左部分为止的最大值
	 {
		 Sum.Left+= L[n].left * L[n - 1].right;
	 }
	 else
	 {
		 Sum.Left = L[n].left * L[n - 1].left+ Sum.Right;
		 if (L[n-1].status[0])//由于第n个骨牌调换了位置,所以状态要改变
		 {
			 L[n-1].status[0] = 0;
		 }
		 else
		 {
			 L[n-1].status[0] = 1;
		 }
	 }
	 if (L[n].right * L[n - 1].left+Sum.Right < L[n].right * L[n - 1].right+ _left)//记录从第1个骨牌到第n+1个骨牌的右部分为止的最大值
	 {
		 Sum.Right = L[n].right * L[n - 1].right+ _left;
	 }
	 else
	 {
		 Sum.Right = L[n].right * L[n - 1].left + Sum.Right;
		 if (L[n-1].status[1])//由于第n个骨牌调换了位置,所以状态要改变
		 {
			 L[n-1].status[1] = 0;
		 }
		 else
		 {
			 L[n-1].status[1] = 1;
		 }
	 }
	 return OK;
}

总体实现:

函数定义

#include
#define OK 1;
#define ERROR 0;
const int LENGTH =6;//骨牌的数目
typedef int Status;
typedef struct _data
{
	int left;//骨牌左边值
	int right;//骨牌右边值
	int status[2];//骨牌的状态
}Data[LENGTH];
typedef struct _Sum
{
	int Left;
	int Right;
}_Sum;
static _Sum Sum = {0,0};
static int Num = LENGTH;
void Init(Data & L)//初始化骨牌
{
	int i;
	for (i = 0; i < LENGTH; i++)
	{
		scanf_s("%d", &L[i].left);
		scanf_s("%d", &L[i].right);
		if (L[i].left <= L[i].right)//初始时将骨牌状态确定
		{
			L[i].status[0] = 0;
			L[i].status[1] = 0;
		}
		else
		{
			L[i].status[0] = 1;
			L[i].status[1] = 1;
		}
	}
}
 Status Recursion(int n ,Data L)//递归操作
{
	 if (n == 0)return ERROR;
	 Recursion(n-1, L);
	 int _left = Sum.Left;//记录第1个骨牌到第n个骨牌的左部分为止的最大值
	 if (L[n].left * L[n - 1].left+Sum.Right < L[n].left * L[n - 1].right+Sum.Left)//记录从第1个骨牌到第n+1个骨牌的左部分为止的最大值
	 {
		 Sum.Left+= L[n].left * L[n - 1].right;
	 }
	 else
	 {
		 Sum.Left = L[n].left * L[n - 1].left+ Sum.Right;
		 if (L[n-1].status[0])//由于第n个骨牌调换了位置,所以状态要改变
		 {
			 L[n-1].status[0] = 0;
		 }
		 else
		 {
			 L[n-1].status[0] = 1;
		 }
	 }
	 if (L[n].right * L[n - 1].left+Sum.Right < L[n].right * L[n - 1].right+ _left)//记录从第1个骨牌到第n+1个骨牌的右部分为止的最大值
	 {
		 Sum.Right = L[n].right * L[n - 1].right+ _left;
	 }
	 else
	 {
		 Sum.Right = L[n].right * L[n - 1].left + Sum.Right;
		 if (L[n-1].status[1])//由于第n个骨牌调换了位置,所以状态要改变
		 {
			 L[n-1].status[1] = 0;
		 }
		 else
		 {
			 L[n-1].status[1] = 1;
		 }
	 }
	 return OK;
}

主函数:

int main()
{	
	int i;
	Data _data;
	Init(_data);//初始化
	Recursion(Num-1, _data);//递归 *** 作
	if (Sum.Left > Sum.Right)
	{
		printf("%d ", Sum.Left);
		for (i = 0; i < Num; i++)
		{
			printf("%d ", _data[i].status[0]);
		}
     }
	else//最后一个骨牌调换位置,状态改变
	{
		printf("%d ", Sum.Right);
		if (_data[Num-1].status[1])
		{
			_data[Num - 1].status[1] = 0;
		}
		else
		{
			_data[Num - 1].status[1] = 1;
		}
		for (i = 0; i < Num; i++)
		{
			printf("%d ", _data[i].status[1]);
		}
	}
	return 0;
}

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/4994781.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-14
下一篇 2022-11-14

发表评论

登录后才能评论

评论列表(0条)

保存