zoukankan      html  css  js  c++  java
  • 【NOIP2007提高组T3】矩阵取数游戏-动态规划+高精度

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

  • 相关阅读:
    2019-01-28 dubbo安装并启动测试
    JAVAWEB项目获取服务器、项目相关路径方法
    Hibernate中的查询方式
    Hibernate在eclipse中的简单运用
    JQuery Tips(2)----关于$()包装集你不知道的
    JQuery Tips(3)----关于$()包装集内元素的改变
    JQuery Tips(4)----一些关于提高JQuery性能的Tips
    利用FireBug使JQuery的学习更加轻松愉快
    asp.net core2 mvc 基础教程--中间件
    asp.net core2 mvc 基础教程--服务注册和管道
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9794020.html
Copyright © 2011-2022 走看看