问题:现有 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<iostream>
#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;
}