(本人本题完成于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;
}