【NOIP2007提高组T3】矩阵取数游戏-动态规划+高精度

来源:互联网 发布:松下网络摄像机出厂ip 编辑:程序博客网 时间:2024/06/08 09:57

(本人本题完成于2016-7-20)

题目大意:对一个n行m列(1≤n,m≤80)的矩阵进行操作,每次在每一行的行首或行尾取出一个数,第i次取数所得的得分为:第1行所取的数*2^i+第2行所取的数*2^i+...+第n行所取的数*2^i,给定一个矩阵,问最后能得到的最大得分。

做法:由题目可以分析得知每一行是相对独立的,我们可以依次求出每一行可以得到的最大得分,再进行累加,就可以得到整个矩阵能得到的最大得分。设f[i][j]为从行首取i个,从行尾取j个的情况下能得到的最大得分,不难得出状态转移方程:f[i][j]=max(f[i-1][j]+a[h][i],f[i][j-1]+a[h][m-j+1]),其中h为当前正在处理的行数,a[1...n][1...m]存储的是矩阵内的元素。我们以取数次数k来划分阶段,每一阶段中求出f[0][k],...,f[i][k-i],...,f[k][0]。注意,操作过程中的数字可能很大,所以要用高精度数来表示。

以下是本人代码(写得比较烂,将就着看看吧......):

#include <cstdio>#include <cstdlib>#include <iostream>#include <algorithm>using namespace std;int n,m,a[90][90]={0};int f[90][90][51]={0};int cmp1[51]={0},cmp2[51]={0},cmp3[51]={0},ans[51]={0},pwr[51]={0};int s1[51]={0},s2[51]={0};int main(){  scanf("%d %d",&n,&m);  for(int i=1;i<=n;i++)    for(int j=1;j<=m;j++)  scanf("%d",&a[i][j]);    for(int h=1;h<=n;h++) //h:当前要处理的行  {    for(int i=1;i<=m;i++)  for(int j=1;j<=m;j++)    for(int k=1;k<=50;k++)      f[i][j][k]=0;for(int i=1;i<=50;i++) pwr[i]=0;pwr[1]=1; //pwr:存储2的次幂for(int k=1;k<=m;k++) //k:表示当前在进行第k次取数{  for(int i=1;i<=50;i++)        pwr[i]*=2;      for(int i=1;i<=50;i++)        if (pwr[i]>=10) {pwr[i+1]+=pwr[i]/10;pwr[i]%=10;}  for(int i=0;i<=k;i++)  {    for(int j=1;j<=50;j++) s1[j]=0;for(int j=1;j<=50;j++) s2[j]=0;for(int j=1;j<=50;j++) cmp1[j]=0;for(int j=1;j<=50;j++) cmp2[j]=0;    for(int j=1;j<=50;j++)  s1[j]=pwr[j]*a[h][i];for(int j=1;j<=50;j++)  if (s1[j]>=10) {s1[j+1]+=s1[j]/10;s1[j]%=10;} //s1=pwr*a[h][i]for(int j=1;j<=50;j++)  s2[j]=pwr[j]*a[h][m-(k-i)+1];for(int j=1;j<=50;j++)  if (s2[j]>=10) {s2[j+1]+=s2[j]/10;s2[j]%=10;} //s2=pwr*a[h][m-(k-i)+1]if (i>0) //特殊判断,防止访问无效内存{  for(int j=1;j<=50;j++)  {    cmp1[j]+=f[i-1][k-i][j]+s1[j];    if (cmp1[j]>=10) {cmp1[j+1]+=cmp1[j]/10;cmp1[j]%=10;}  } //cmp1=f[i-1][k-i]+a[h][i]*pwr=f[i-1][k-i]+s1}if (k-i>0) //特殊判断,防止访问无效内存{  for(int j=1;j<=50;j++)  {    cmp2[j]+=f[i][k-i-1][j]+s2[j];    if (cmp2[j]>=10) {cmp2[j+1]+=cmp2[j]/10;cmp2[j]%=10;}  } //cmp2=f[i][k-i-1]+a[h][m-(k-i)+1]*pwr=f[i][k-i-1]+s2}bool flag=0;for(int j=50;j>=1;j--)        {          if (cmp1[j]>cmp2[j]) {flag=1;break;}  if (cmp1[j]<cmp2[j]) {flag=0;break;}        } //比较两个高精度数的大小if (flag){  for(int j=1;j<=50;j++)    f[i][k-i][j]=cmp1[j];}else{  for(int j=1;j<=50;j++)    f[i][k-i][j]=cmp2[j];}  }}for(int i=1;i<=50;i++) cmp3[i]=0;for(int i=0;i<=m;i++){  bool flag=0;  for(int j=50;j>=1;j--)  {if (f[i][m-i][j]>cmp3[j]) {flag=1;break;}if (f[i][m-i][j]<cmp3[j]) {flag=0;break;}  }  if (flag)  {for(int j=1;j<=50;j++)cmp3[j]=f[i][m-i][j];  }} //求出该行最大得分for(int i=1;i<=50;i++)  ans[i]+=cmp3[i];for(int i=1;i<=50;i++)  if (ans[i]>=10) {ans[i+1]+=ans[i]/10;ans[i]%=10;} //将该行最大得分累加进最终解  }    bool flag=0;  for(int i=50;i>=1;i--)  {    if (!flag&&ans[i]>0) flag=1;if (flag) printf("%d",ans[i]);  }  if (!flag) printf("0"); //结果可能为0,特殊判断    return 0;}

0 0
原创粉丝点击