zoukankan      html  css  js  c++  java
  • Luogu P1005 矩阵取数游戏

    Description:

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

    1. 每次取数时须从每行各取走一个元素,共nn个。经过mm次后取完矩阵内所有元素;
    2. 每次取走的各个元素只能是该元素所在行的行首或行尾;
    3. 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值×2^i ,其中i表示第i次取数(从1开始编号);
      游戏结束总得分为m次取数得分之和。
      帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。

    Analysis:

    贪心不行:如果有一组数据是4,3,10,1,1,1,1,1,1,1,1,5,5,5,5,9贪心就是错的,会先把5取完,然而应该先取1。
    前面的状态对后面有影响,这已经失去了贪心的条件。
    DP:区间变为[i,j]时的最大得分
    上一次可以从i-1取,也可以从j+1取,所以 f[i][j] 由 f[i-1][j] 和 f[i][j+1] 转移来。
    f[i][j] = max( f[i-1][j] + a[i-1]×2^g ,f[i][j+1] + a[j+1]×2^g )
    g表示第几次,g = m-j+i-1,即取走元素的个数。

    Code

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define ll long long
    using namespace std;
    const int MAX_N = 81;
    ll a[MAX_N],f[MAX_N][MAX_N],p[MAX_N],n,m,ans;
    void solve()
    {
    	memset(f,0,sizeof(f));
    	for(int i = 1;i <= m;++i)
    	{
    		for(int j = m;j >= i;--j)
    		{
    			f[i][j] = max(f[i-1][j] + a[i-1]*p[m-j+i-1],f[i][j+1] + a[j+1]*p[m-j+i-1]);
    		}
    	}
    	ll maxn = 0;
    	for(int i = 1;i <= m;++i) maxn = max(maxn,f[i][i] + a[i]*p[m]);
    	ans += maxn;
    }
    int main()
    {
    	scanf("%lld%lld",&n,&m);
    	p[0] = 1;
    	for(int i = 1;i <= 64;++i) p[i] = p[i-1] << 1;
    	for(int i = 1;i <= n;++i)
    	{
    		for(int j = 1;j <= m;++j)	scanf("%lld",&a[j]);	
    		solve();
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
    岂能尽如人意,但求无愧我心
  • 相关阅读:
    调研一类软件的发展演变—聊天软件( 1000-2000 words, in Chinese)
    C++用法的学习心得(要求包含示例,并反映出利用网络获取帮助的过程)
    软件工程学习总结
    南通大学教务管理微信公众号体验
    设计一款给爸爸妈妈用的手机
    第二次作业
    web browser 发展史
    c++用法的学习心得
    电梯调度
    一个数组既有正数也有负数,计算出它的子数组和的最大值。
  • 原文地址:https://www.cnblogs.com/Zforw/p/11298821.html
Copyright © 2011-2022 走看看