给一个矩阵,找到从左上到右下角的路径
使得路径上的数字乘积0最少, 每次只能从当前位置到右侧或下侧相邻位置
首先要想到乘积为0对应因子为2、5
我刚开始的思路是每次找到与当前位置数所得结果0最少的,也就是2、 5一起考虑
但这样写不仅太复杂,而且是不对的
正解应该是分别考虑2最少的和5最少的情况
这道题卡了好几天。。。
另外有个坑就是矩阵中可能含0,这时结果肯定为经过0的路径,且答案为1
代码能力太挫。。。写了近200行
代码如下:
/* ***********************************************
Author : yinwoods
E-Mail : yinwoods@163.com
Created Time : 2014年12月15日 星期一 19时48分02秒
File Name : 2B.cpp
************************************************ */
#include <cmath>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAXN 1010
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
int a[MAXN][MAXN];
struct DP {
int val, from;//记录前一个状态位置,1表示从左侧来,2表示从上方来
}dp2[MAXN][MAXN], dp5[MAXN][MAXN];
int main(void) {
int n;
int x0, y0;
bool ok0 = false;
scanf("%d", &n);
for(int i=1; i<=n; ++i) {
for(int j=1; j<=n; ++j) {
scanf("%d", &a[i][j]);
int tmp = a[i][j];
if(tmp == 0) {//如果含0,记录位置
x0 = i;
y0 = j;
ok0 = true;
continue;
}
if(tmp%2 == 0) {
while(tmp%2 == 0) {
tmp /= 2;
++dp2[i][j].val;//对应找到2最少的路径的DP
}
}
if(tmp%5 == 0) {
while(tmp%5 == 0) {
tmp /= 5;
++dp5[i][j].val;//对应找到5最少的路径的DP
}
}
}
}
for(int i=2; i<=n; ++i) {
dp2[1][i].val += dp2[1][i-1].val;
dp2[1][i].from = 1;
dp2[i][1].val += dp2[i-1][1].val;
dp2[i][1].from = 2;
dp5[1][i].val += dp5[1][i-1].val;
dp5[1][i].from = 1;
dp5[i][1].val += dp5[i-1][1].val;
dp5[i][1].from = 2;
}
for(int i=2; i<=n; ++i) {
for(int j=2; j<=n; ++j) {
int tmp1 = dp2[i-1][j].val;
int tmp2 = dp2[i][j-1].val;
if(tmp1 < tmp2) {
dp2[i][j].val += tmp1;
dp2[i][j].from = 2;
} else {
dp2[i][j].val += tmp2;
dp2[i][j].from = 1;
}
tmp1 = dp5[i-1][j].val;
tmp2 = dp5[i][j-1].val;
if(tmp1 < tmp2) {
dp5[i][j].val += tmp1;
dp5[i][j].from = 2;
} else {
dp5[i][j].val += tmp2;
dp5[i][j].from = 1;
}
}
}
/*
for(int i=1; i<=n; ++i) {
for(int j=1; j<=n; ++j)
printf("%d ", dp2[i][j].val);
puts("");
}
*/
int x, y;
string ans;
x = y = n;
while(x!=1 || y!=1) {
int tmp = dp2[x][y].from;
if(tmp == 1) {
ans.push_back('R');
--y;
} else {
ans.push_back('D');
--x;
}
}
string ans2 (ans.rbegin(), ans.rend());//找到2最少的路径
//printf("2 -- %d\t", dp2[n][n].val);
//cout << ans2 << endl;
ans.clear();
x = y = n;
while(x!=1 || y!=1) {
int tmp = dp5[x][y].from;
if(tmp == 1) {
ans.push_back('R');
--y;
} else {
ans.push_back('D');
--x;
}
}
string ans5(ans.rbegin(), ans.rend());//找到5最少的路径
//printf("5 -- %d\t", dp5[n][n].val);
//cout << ans5 << endl;
struct RES {
int two, five;
RES() {
two = five = 0;
}
}res2, res5;
x = y = 1;
for(int i=0; ; ++i) {//从路径推出结果含0个数
int tmp = a[x][y];
//printf("%d\n", tmp);
while(tmp && tmp%2 == 0) {
++res2.two;
tmp /= 2;
}
tmp = a[x][y];
while(tmp && tmp%5 == 0) {
++res2.five;
tmp /= 5;
}
if(i >= ans2.size())
break;
if(ans2[i] == 'D') {
++x;
} else ++y;
}
x = y = 1;
for(int i=0; ; ++i) {//从路径推出结果含0个数
int tmp = a[x][y];
//printf("%d\n", tmp);
while(tmp && tmp%2 == 0) {
++res5.two;
tmp /= 2;
}
tmp = a[x][y];
while(tmp && tmp%5 == 0) {
++res5.five;
tmp /= 5;
}
if(i >= ans5.size())
break;
if(ans5[i] == 'D') {
++x;
} else ++y;
}
//printf("%d - %d\n", res2.two, res2.five);
//printf("%d - %d\n", res5.two, res5.five);
int tmp1 = min(res2.two, res2.five);
int tmp2 = min(res5.two, res5.five);
if(ok0 && min(tmp1, tmp2)>1) {//如果矩阵中含0
puts("1");
for(int i=1; i<x0; ++i) {
printf("D");
}
for(int i=1; i<y0; ++i) {
printf("R");
}
for(int i=x0; i<n; ++i) {
printf("D");
}
for(int i=y0; i<n; ++i)
printf("R");
}
else if(tmp1 < tmp2) {
cout << tmp1 << endl << ans2 << endl;
} else {
cout << tmp2 << endl << ans5 << endl;
}
return 0;
}