取数游戏

来源:互联网 发布:网络歌手受排挤 编辑:程序博客网 时间:2024/05/02 00:19
 【训练题】取数游戏  
时间限制:1秒  内存限制:64M    

 

 

 

 

【问题描述】

 

 


  帅帅经常跟同学玩一个取数游戏:对于一个给定的长度为n的整数序列,每个元素a[i]为非负整数。游戏规则如下:

  1、每次取数时须从取走一个元素,共取n次;
  2、每次取走的元素只能是当前序列的首或尾元素;
  3、每次取数都有一个得分值,取数的得分=被取走的元素值*2^i,其中i表示第i次取数(从1开始编号);
  4、游戏结束总得分为n次取数得分之和。

  帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。

 

 

 

 

【输入格式】

 

 


  第一行一个整数n,表示整数序列的长度。
  第二行有n个用空格分开的非负整数,表示整数序列

 

 

 

 

【输出格式】

 

 


  一个整数,表示最大得分。

 

 

 

 

【输入样例】

 

 


4
4 5 0 5

 

 

 

 

【输出样例】

 

 


122

 

 

 

 

【数据范围】

 

 


  n<=20
  0<=a[i]<=1000


 

 

 

这道题是一道区间动规

按照顺序处理这道题十分困难,反正我是没做出来。正方向难,我们就反着来;

反着来,我们就从最后一个元素倒着取,然后取倒数第二个,然后倒数第三个。。。。

一道区间动规题,我们就可以设状态转移方程为f(i,j)表示第i个数到第j个数的能取出的最大值;

现在假如我们还剩下两个数没取,我们可以先取前面那个数,然后再取后面那个数;我们也可以先取后面那个数,再取前面那个数;

那么,状态转移方程就出来了  f(i,j)=MAX{ f(i+1,j)+取a[i]的值 , f(i,j-1)+取a[j]的值 }

关于取a[i]的值该怎么计算呢?现在我们计算的是区间[i,j]的值,那么区间[i,j]中有j-i+1个元素,那么已经取走了N-j+i-1个元素,所以说

a[i]就是第N-j+i个元素,那么取走a[i]的值就是a[i]*2^(N-j+i)

所以状态转移方程最后就写为 f(i,j)=MAX{ f(i+1,j)+a[i]*2^(N-j+i) , f(i,j-1)+a[j]*2^(N-j+i) }

 

边界:f(i,i)=a[i]*2^N;

最后答案:f(1,N);

 

易错点:这道题,不能按照顺序扫描i,j,而是要按照区间大小从小到大扫描,即区间长度为2的先扫,然后区间长度为3的,然后为4的。。。。仔细想想为什么

 

程序:

#include<iostream>#include<cstdio>#include<cstring>using namespace std;int N;int a[25];long long d[30][30];long long mi(int x){ long long ans=1; for(int i=1;i<=x;i++)  ans*=2;  return ans;}void Ready(){ scanf("%d",&N); for(int i=1;i<=N;i++)  scanf("%d",&a[i]); memset(d,0,sizeof(d)); for(int i=1;i<=N;i++)  d[i][i]=a[i]*mi(N);}int MAX(int x,int y){ return x>y ? x:y;}void Working(){ for(int i=1;i<N;i++)  for(int j=1;j<=N && i+j<=N;j++)   {    d[j][i+j]=MAX(d[j+1][i+j]+a[j]*mi(N-i),d[j][i+j-1]+a[i+j]*mi(N-i));   }   cout<<d[1][N];}int main(){ Ready(); Working(); return 0;} 


by:重庆一中吴松隐

0 0
原创粉丝点击