P1005 矩阵取数游戏

8 篇文章 0 订阅

题目描述

帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的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行,为一个整数,即输入矩阵取数后的最大得分。



贪心地去取每行不一定最优--

用区间dp,,f[i][j]:左边取到i右边取到j最优解

高精度运算

记得特判输出0。。。GG

#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<map>
#include<stack>
#include<set>
#include<cmath>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;

const int maxn = 101;

struct data{
	int len,a[maxn];
	data() {len = 0; memset(a,0,sizeof(a));}
	data operator = (const int &k) {
		len = 0;
		int K = k;
		while (K) {
			a[len++] = K % 10;
			K /= 10;
		}
	}
	data operator + (const data &b) {
		data c;
		int Len = max(len,b.len);
		for (int i = 0; i < Len; i++) {
			c.a[i] += a[i] + b.a[i];
			c.a[i + 1] += c.a[i] / 10;
			c.a[i] %= 10;
		}
		c.len = c.a[Len]?Len+1:Len;
		return c;
	}
	data operator * (const data &b) {
		data c;
		for (int i = 0; i < len; i++)
			for (int j = 0; j < b.len; j++) {
				int TT = a[i];
				c.a[i+j] += a[i]*b.a[j];
				c.a[i+j+1] += c.a[i+j] / 10;
				c.a[i+j] %= 10;
			}
		c.len = c.a[len+b.len-1]?len+b.len:len+b.len-1;
		return c;
	}
	bool operator < (const data &b) {
		if (len < b.len) return 1;
		if (len > b.len) return 0;
		for (int i = len - 1; i >= 0; i--) {
			if (a[i] < b.a[i]) return 1;
			if (a[i] > b.a[i]) return 0;
		}
		return rand()%2;
	}
}ans,t[maxn][maxn],f[maxn][maxn],two[maxn];

int n,m;

void Solve(int k)
{
	for (int i = 0; i <= m; i++)
		for (int j = m + 1; j > i; j--) {
			f[i][j] = 0;
			int ti = i + m - j + 1;
			if (i) f[i][j] = f[i-1][j] + two[ti]*t[k][i];
			if (j <= m) {
				data now = f[i][j+1] + two[ti]*t[k][j];
				if (f[i][j] < now) f[i][j] = now;
			}
		}
	data Max; Max = 0;
	for (int i = 0; i <= m; i++)
		if (Max < f[i][i+1])
			Max = f[i][i+1];
	ans = ans + Max;
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
	#endif
	
	cin >> n >> m;
	for (int i = 1; i <= n; i++) 
		for (int j = 1; j <= m; j++) {
			int x; scanf("%d",&x);
			t[i][j] = x;
		}
	two[1] = 2;
	for (int i = 2; i <= m; i++)
		two[i] = two[i-1]*two[1];
	for (int i = 1; i <= n; i++)
		Solve(i);
	if (!ans.len) {puts("0"); return 0;}
	for (int i = ans.len - 1; i >= 0; i--) 
		printf("%d",ans.a[i]);
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值