• 矩阵取数


    Description

    帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n·m的矩阵,矩阵中的每个元素aij据为非负整数。游戏规则如下:

    1. 每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有的元素;
    2. 每次取走的各个元素只能是该元素所在行的行首或行尾;
    3. 每次取数都有一个得分值,为每行取数的得分之和;每行取数的得分 = 被取走的元素值*2i,其中i表示第i次取数(从1开始编号);
    4. 游戏结束总得分为m次取数得分之和。

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

    Analysis

    因为每行取数的策略可能不同,所以应该分行进行动规讨论。每行都要进行m次取数,每次取数的权值都是上一次的二倍。因为取数的分数是累计的,所以每次取完数后剩下部分也要求出最优策略,具备最优解子结构。那么

    dp[i][j]=2*max(s[i]+dp[i+1][j],s[j]+dp[i][j-1])
    

    到这里还没有结束,因为m<=80,所以最大是2^80,约合30位,所以高精度计算。

    很坑的地方:因为状态转移中存在do[i+1][j],所以可能会数组越界,不能开到81。

    Code

    #include <bits/stdc++.h>
    
    int n,m,s[1001];
    
    struct bign{
    	int len,num[101];
    	bign operator = (bign eq){
    		len=eq.len;
    		memset(num,0,sizeof(num));
    		for(int i=0;i<len;i++)
    			num[i]=eq.num[i];
    		return *this;
    	}
    	bign operator + (bign ad){
    		bign ans;
    		ans.len=std::max(len,ad.len);
    		memset(ans.num,0,sizeof(ans.num));
    		int accu=0;
    		for(int i=0;i<ans.len;i++){
    			int res=num[i]+ad.num[i]+accu;
    			ans.num[i]=res%10;
    			accu=res/10;
    		}
    		if(accu)ans.num[ans.len++]=accu;
    		return ans;
    	}
    	bign operator + (int ad){
    		bign eq;
    		eq.len=0;
    		memset(eq.num,0,sizeof(eq.num));
    		while(ad){
    			eq.num[eq.len++]=ad%10;
    			ad/=10;
    		}
    		return *this+eq;
    	}	
    	bign operator += (bign ad){
    		return *this=*this+ad;
    	}
    	bign operator += (int ad){
    		return *this=*this+ad;
    	}
    	bool operator > (bign ad){
    		if(len>ad.len)return 1;
    		if(len<ad.len)return 0;
    		for(int i=len-1;i>=0;i--)
    			if(num[i]>ad.num[i])return 1;
    			else if(num[i]<ad.num[i])return 0;
    		return 0;
    	} 
    	friend std::ostream& operator << (std::ostream& out,bign ans){
    		for(int i=ans.len-1;i+1;i--)
    			out<<ans.num[i];
    		return out;
    	}
    }ans,dp[81][81];
    
    int main(){
    	freopen("game.in","r",stdin);
    	freopen("game.ans","w",stdout);
    	std::cin>>n>>m;
    	while(n--){
    		for(int i=1;i<=m;i++)
    			std::cin>>s[i];
    		for(int l=1;l<=m;l++)
    			for(int b=1;b<=m-l+1;b++){
    				int e=b+l-1;
    				bign la,ra;
    				la=dp[b+1][e]+s[b];
    				ra=dp[b][e-1]+s[e];
    				dp[b][e]=la>ra?la+la:ra+ra;
    			}
    		ans+=dp[1][m];
    	}
    	std::cout<<ans<<std::endl;
    	return 0;
    }
    
  • 相关阅读:
    字典和列表 相互嵌套
    HashSet
    SQLServer在分页获取数据的同时获取到总记录数
    C# list 多条件排序
    DictionaryBase
    .Net页面数据校验类(WebForm)
    链接
    解决:Server's certificate is not trusted
    win10下gradle6.2版本下载安装配置
    解决:mysql5.7乱码中文
  • 原文地址:https://www.cnblogs.com/qswx/p/9492520.html
Copyright © 2020-2023  润新知