2007OI, 矩阵取数游戏( 区间DP )

Problem Description:
帅帅经常跟同学玩一个矩阵取数游戏,对于一个给定的n*m的矩阵,矩阵中每个元素Aij为非负整数。游戏规则如下:
1.每次取数时须从每行各去走一个元素,共N个.M次后取完矩阵所有元素;
2.每次取数都是一个得分值,为每行取数的得分之和,每行取数的得分=被取走的元素值*2(2
右上角有个i),其中i表示第i次取数(从1开始编号)
3.每次取走的各个元素只能是该原素所在行的行首或行尾.
4.游戏结束总得分为M次取数得分之和

dp[i][j][k]表示当前行的在【i,j】区间内去k个数所取得的最大值
dp[i][j][k] = max(dp[i+1][j][k-1], dp[i][j-1][k-1])
ans = sum{dp[1][col][col]}.

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

#define MAXN    100
//BigInteger
int row, col;
int dp[MAXN][MAXN][MAXN], val[MAXN][MAXN];

int dfs(int row_idx, int start, int final, int cnt)
{
        int left_rst, right_rst, base(1<<(col-cnt+1));
        if( start == final ) {
                return base*val[row_idx][start];
        }
        if( -1 != dp[start][final][cnt] ) {
                return dp[start][final][cnt];
        }
        left_rst = val[row_idx][start]*base+dfs(row_idx, start+1, final, cnt-1);
        right_rst = val[row_idx][final]*base+dfs(row_idx, start, final-1, cnt-1);
        return dp[start][final][cnt] = max(left_rst, right_rst);
}

int main(int argc, char const *argv[])
{
#ifndef ONLINE_JUDGE
        freopen("test.in", "r", stdin);
#endif
        int rst;
        while( ~scanf("%d %d", &row, &col) ) {
                for(int i = 1; i <= row; i ++) {
                        for(int j = 1; j <= col; j ++) {
                                scanf("%d", &val[i][j]);
                        }
                }
                rst = 0;
                for(int i = 1; i <= row; i ++) {
                        memset(dp, -1, sizeof(dp));
                        rst += dfs(i, 1, col, col);
                }
                printf("%d\n", rst);
        }
        return 0;
}
这一个只能做对60%的测试数据,要Accepted 需要使用高精度

import java.io.*;
import java.util.*;
import java.math.*;


public class Main {


        static int col;
        static int MAXSIZE = 81;
        static int[][] val = null;
        static BigInteger[][][] dp = null;


        public static BigInteger dfs(int row_idx, int s, int f, int cnt) {
                BigInteger left_rst, right_rst, base;
                base = BigInteger.valueOf(1);
                for(int i = 0; i < (col-cnt+1); i ++) {
                        base = base.multiply(BigInteger.valueOf(2));
                }
                if( s == f ) {
                        return base.multiply(BigInteger.valueOf(val[row_idx][s]));
                }
                if( 0 != dp[s][f][cnt].compareTo(BigInteger.valueOf(-1)) ) {
                        return dp[s][f][cnt];
                }
                left_rst = base.multiply(BigInteger.valueOf(val[row_idx][s]));
                left_rst = left_rst.add(dfs(row_idx, s+1, f, cnt-1));
                right_rst = base.multiply(BigInteger.valueOf(val[row_idx][f]));
                right_rst = right_rst.add(dfs(row_idx, s, f-1, cnt-1));
                return dp[s][f][cnt] = left_rst.max(right_rst);
        }


        public static void main(String args[]) {
                int row, init = -1;
                BigInteger rst;
                val = new int[MAXSIZE][MAXSIZE];
                dp = new BigInteger[MAXSIZE][MAXSIZE][MAXSIZE];
                Scanner cin = new Scanner(System.in);
                while( cin.hasNext() ) {
                        row = cin.nextInt(); col = cin.nextInt(); rst = BigInteger.valueOf(0);
                        for(int i = 1; i <= row; i ++) {
                                for(int j = 1; j <= col; j ++) {
                                        val[i][j] = cin.nextInt();
                                }
                        }
                        for(int i = 1; i <= row; i ++) {
                                for(int j = 0; j <= col; j ++) {
                                        for(int k = 0; k <= col; k ++) {
                                                for(int z = 0; z <= col; z ++) {
                                                        dp[j][k][z] = BigInteger.valueOf(-1);
                                                }
                                        }
                                }
                                rst = rst.add(dfs(i, 1, col, col));
                        }
                        System.out.println(rst);
                }
        }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值