逃离地牢

题目描述

小明明又被大威鱼抓住了,大威鱼把小明明关在地牢里,地牢由n * n 个房间组成,小明被困在地牢的最左上角的房间中,出口在最右下角,他想逃出这个诡异的地牢,但是他只能向下或者向右走。
小明每经过一个房间,都要受到一定的伤害(伤害都大于0),而且这个伤害可不是累加的哦,是累乘的,因此当他走出地牢的时候,他受到的伤害会非常大。但是小明有一个终极技能,能把受到的伤害X转变为金币,转化如下。
int val( type x )
{
  int ret = 0;
  while(x % 12 == 0) {
    x /= 12;
    ret++;
  }
  return ret;
}
请问小明最多能得到多少金币?

输入

输入包含多组测试用例,每组测试用例的第一行是一个整数n(n <= 50),接下来n行每行n个正整数 (<= 10 ^ 9) 表示每个房间对小名造成的伤害,当n 为 0 时输入结束。

输出

先输出Case,Case数从1开始,再输出小明获得的最大金币,具体输出形式见样例。

样例输入

3
12 1 24
6 3 4
4 4 16
0

样例输出

Case #1: 3

12 可以质因数分解为2 ^ 2 , 3所以就是找2和 3的数量最小值的最大,状态转移方程就是当前因子数= max(上一步,现在);


# include <iostream>
# include <cstdio>
# include <algorithm>
# include <cstring>

using namespace std;

const int maxn = 1e2 + 10;
int dp[maxn][maxn][2010];
int f[maxn][maxn][2];
int main(int argc, char *argv[])
{
    int n;
    int ca = 1;
    while(cin >> n, n)
    {


        int ans = 0;
        memset(f, false, sizeof(f));
        memset(dp,-1, sizeof(dp));
        for(int i = 1; i <= n; i++)
            for(int j = 1; j <= n; j++)
            {
                int x;
                cin >> x;
                int k1 = 0, k2 = 0;
                while(x % 2 == 0)
                {
                    x /= 2;
                    k1++;
                }
                while(x % 3 == 0)
                {
                    x /= 3;
                    k2++;
                }
                f[i][j][0] = k1;//2的个数
                f[i][j][1] = k2;//3的个数
            }



        for(int i = 0; i <= n; i++)
            for(int j = 0; j <= n; j++)
                dp[i][j][0] = 0;
        for(int i = 0; i <= n; i++)
        {
            for(int j = 0; j <= n; j++)
            {
                for(int p = f[i][j][0]; p <= 2000; p++)
                {
                    if(i == 0 || j == 0)
                    {
                        continue;
                    }
                    if(dp[i - 1][j][p - f[i][j][0]] != -1)//当前我这一步的2因子数是由上一步的2的因子数结合而来的,3的因子数也是
                    {
                        dp[i][j][p] = max(dp[i][j][p], dp[i - 1 ][j][p - f[i][j][0]] + f[i][j][1]);
                    }
                    if(dp[i][j - 1][p - f[i][j][0]] != -1)//当前我这一步的2因子数是由上一步的2的因子数结合而来的,3的因子数也是
                    {
                        dp[i][j][p] = max(dp[i][j][p], dp[i][j - 1][p - f[i][j][0]] + f[i][j][1]);
                    }
                }
            }
        }
       for(int i = 0; i <= 2000; i++)
           ans = max(min(dp[n][n][i],i / 2), ans);
        cout<<"Case #"<<ca++<<": "<<ans<<endl;

    }
    return 0;
}


 

展开阅读全文

没有更多推荐了,返回首页