noip 2007矩阵取数游戏luogu1005

http://www.elijahqi.win/archives/440
题目描述
帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数。游戏规则如下:
1.每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有元素;
2.每次取走的各个元素只能是该元素所在行的行首或行尾;
3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*2^i,其中i表示第i次取数(从1开始编号);
4.游戏结束总得分为m次取数得分之和。
帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。
输入输出格式
输入格式:

输入文件game.in包括n+1行:
第1行为两个用空格隔开的整数n和m。
第2~n+1行为n*m矩阵,其中每行有m个用单个空格隔开的非负整数。
数据范围:
60%的数据满足:1<=n, m<=30,答案不超过10^16
100%的数据满足:1<=n, m<=80,0<=aij<=1000

输出格式:

输出文件game.out仅包含1行,为一个整数,即输入矩阵取数后的最大得分。

输入输出样例
输入样例#1:
2 3
1 2 3
3 4 2
输出样例#1:
82
这题要写一个高精度,高精度乘法我们可以用多次加法代替,这样比较好写

题解:
题目中每次取数的得分因每次均从行首或者行尾取 故可以累加每行的得分求最后总的m次取数的分之和。

方案一:
根据题目 写出简单方程式 进行dp

f(i,j)表示 对i~j这些整数进行 j-i+1次操作后结果的最大值

优化①:提前将2的次方计算出并储存至数组中备用

根据分析题目 题目数据范围m<=80 即最高可能产生的大小,据运算位数为35位即使longlong也无法存下 故本题考虑高精度。

由于需要使用高精度乘法及高精度加法故本题对于程序编写难度要求很高。

#include
#include
#include
char ans[30],anss[30],sum[30],a[88][10],data[88][88][30];int aa,n,m;
bool ff[88][88];
void plus(char j1[],char j2[]){
    int max=0,x1,x2,jw=0,tmp=0;
    int l1=strlen(j1);
    int l2=strlen(j2);
    if(l1>l2) max=l1; else max=l2;
    for (int i=1;i<=max;++i){
        if (l1-i>=0) x1=j1[l1-i]-48; else x1=0;
        if (l2-i>=0) x2=j2[l2-i]-48; else x2=0;
        tmp=(x1+x2+jw)%10;
        if(x1+x2+jw>=10) jw=1;else jw=0;

        ans[max-i]=tmp+48;

    }
    if (jw!=0) {
        for (int  i=max;i>=1;--i) ans[i]=ans[i-1];
        ans[0]=49;
        ans[max+1]='\0';
        //printf("%s",ans);
        return;
    }
    ans[max]='\0';
    //printf("%s",ans);
}
void  maxx(char j1[],char j2[]){
    int l1=strlen(j1);
    int l2=strlen(j2);
    if (l1>l2) {
        strcpy(anss,j1);
        //for (int i=0;i
        return;
    }
    if (l1strcpy(anss,j2);
        //for (int i=0;i
        return;
    }
    for (int i=0;iif (j1[i]>j2[i]){
            strcpy(anss,j1);
            //for (int i=0;i
            return;
        }
        if (j1[i]strcpy(anss,j2);
            //for (int i=0;i
            return;
        }
    }
    strcpy(anss,j2);
}
void f(int i,int j){
    if (i==j){
        plus(a[i],a[i]);
        strcpy(data[i][j],ans);
        //plus(data[i][j],ans);
        ff[i][j]=true;
        return;
    }
    char tmp[30]="",tmp1[30]="";
    if (ff[i+1][j]==false) f(i+1,j);
    //f(i+1,j);
    plus(data[i+1][j],a[i]);
    strcpy(tmp,ans);
    plus(tmp,tmp);
    //int l=strlen(ans);
    strcpy(tmp1,ans);
    //for (int i=1;i
    if (ff[i][j-1]==false) f(i,j-1);
    //f(i,j-1);
    plus(data[i][j-1],a[j]);
    strcpy(tmp,ans);
    plus(tmp,tmp);
    maxx(ans,tmp1);
    strcpy(data[i][j],anss);
    ff[i][j]=true;
}
int main(){
    freopen("game.in","r",stdin);
    freopen("game.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;++i){
        for (int j=1;j<=m;++j) {
            scanf("%d",&aa);
            sprintf(a[j], "%d", aa);    
            //itoa(aa,a[j],10);
            //printf("%s ",a[j]);
        }
        memset(ff,false,sizeof(ff));

        f(1,m);
        plus(sum,data[1][m]);
        strcpy(sum,ans);
    }
    printf("%s",sum);

    return 0;
}

你可能感兴趣的:(动态规划)