/* 题目:多边形游戏 作者:梁栋 版本:VS2008 状态转移式: min(max)_sum[i][j] ,表示从i数逆时针数j个的链条合并的最小或者最大值 方法: 从i到i+j-1中找一个运算符断开,会有两种情况. 情况一: 运算符为 +, 则整个链条的最大或者最小值等于两个子链条的最大或者最小值的和 情况二: 运算符为 *, 则整个链条的最大或者最小值等于两个子链条的最大值与最小值的组合中的最大与最小值, 因为可能两个子链条的最大值都是负数,那么这时候并不是他们俩的乘积最大,而是两个子链条的 最小值相乘得到一个很大的正数. 终极子问题: min(max)_sum[i][1], i change from 1 to n, 即从每个数值逆时针数1个的最大最小值都是这个数值本身. 最终要得到的结果是: min(max) {min(max)_sum[i][n]}, min(max)_sum[i][n]表示从第i个数值逆时针数遍整个链条,而i与(i+n-1)%n这个边不参与合并的值。 我们从中取min(max),意思是从去掉第i(1 to n)边 合并整个链条的min(max)_sum中取一个最大或者最小的就是我们按照游戏规则的最终解. */ #include <iostream> #include <vector> #include <algorithm> #include <utility> using namespace std; int min_sum[50][50]; // min_sum[i][j] 表示从第i个数数起,沿逆时针方向数j个的链条的合并后最小值 int max_sum[50][50]; // max_sum[i][j] 表示从第i个数数起,沿逆时针方向数j个的链条的合并后最大值 vector<pair<int,char>> _vec; //存储顶点数值与相邻运算符,按逆时针看 vector<int> local_vec;//用于DP过程临时计算最大最小值用 int n;// 多边形的边数(顶点数) int _max,_min; //存储最终整个链条的最大最小合并值 void input_poly() { //给_vec[0]随便输个值,我们只用1...n _vec.push_back(make_pair(-99,'#')); _max=-99999; _min=99999; cout<<"输入多边形的边数(即顶点数):"; cin>>n; int i=1; char ch; int num; cout<<"从某个顶点开始,逆时针输入数值与符号,根据提示操作!"<<endl; while(i<=n) { cout<<"输入第"<<i<<"个"<<"数值与操作符,空格隔开:"; cin>>num>>ch; _vec.push_back(make_pair(num,ch)); ++i; } } void min_max_poly_dp() { //做一些DP的初始化工作 for(int i=1;i<=n;++i) { max_sum[i][1]=min_sum[i][1]=_vec[i].first; } //DP过程 for(int j=2;j<=n;++j) { for(int i=1;i<=n;++i) { min_sum[i][j]=99999; max_sum[i][j]=-99999; for(int k=1;k<=j-1;++k) { //如果此处断开符号为+号,则可以直接使用最大最小 if(_vec[(i+k-1)%n].second=='+') { if(min_sum[i][k]+min_sum[(i+k)%n][j-k]<min_sum[i][j]) { min_sum[i][j]=min_sum[i][k]+min_sum[(i+k)%n][j-k]; } if(max_sum[i][k]+max_sum[(i+k)%n][j-k]>max_sum[i][j]) { max_sum[i][j]=max_sum[i][k]+max_sum[(i+k)%n][j-k]; } } //如果此处断开符号为*,则从4种可能运算中找到最大最小,由于负数的影响,所以必须尝试4种! else { local_vec.push_back(min_sum[i][k]*min_sum[(i+k)%n][j-k]); local_vec.push_back(min_sum[i][k]*max_sum[(i+k)%n][j-k]); local_vec.push_back(max_sum[i][k]*max_sum[(i+k)%n][j-k]); local_vec.push_back(max_sum[i][k]*min_sum[(i+k)%n][j-k]); sort(local_vec.begin(),local_vec.end()); if(local_vec[0]<min_sum[i][j]) { min_sum[i][j]=local_vec[0]; } if(local_vec[3]>max_sum[i][j]) { max_sum[i][j]=local_vec[3]; } local_vec.clear(); } } } } //到此min_sum[i][n],max_sum[i][n], i change from 1 to n 已经全部计算得到, 下面从中找到最小的min_sum[i][n]赋值给min,找到最大的max_sum[i][n]赋值给max, _max=-99999; _min=99999; for(int i=1;i<=n;++i) { if(min_sum[i][n]<_min) { _min=min_sum[i][n]; } if(max_sum[i][n]>_max) { _max=max_sum[i][n]; } } cout<<"最大值:"<<_max<<endl; cout<<"最小值:"<<_min<<endl; _vec.clear(); } int main() { input_poly(); min_max_poly_dp(); return 0; }