
问题:现有 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;
}
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)