问题:现有 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条)