题目描述
小明明又被大威鱼抓住了,大威鱼把小明明关在地牢里,地牢由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;
}