cf contest2 B

http://codeforces.com/problemset/problem/2/B

求从左上角到右下角所经过的数字之积末尾所含0最小的个数

10=2*5

dp[i][j][0]代表走到i,j位置,所得2的最小和,

dp[i][j][1]代表走到i,j位置,所得5的最小和,

最后得到的最小个数是min(dp[n][n][0],dp[n][n][1]);

还要用每个数初始化dp数组哦

但是可能会有0,这是一个trick;

如果存在零,那么最小个数一定是小于等于1

所以先判断是否有0存在,如果这个数字为0的,就将它改为10=2*5,

最后根据是否有零,判断就好

还要输出路径

输出有零的路径比较简单,可以一开始标记一个0的位置就行了

没有的零的话

就比较dp[i-1][j][0]和dp[i][j-1][0](也可能是1)

然后得到路径

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int n;
int flag=0,x,y;
int map[1001][1001];
int dp[1001][1001][2];
char ways[2002];
int main(void)
{
//freopen("in.txt","r",stdin);
cin >> n;
for(int i = 1;i<=n;i++)
for(int j = 1;j<=n;j++)
{
scanf("%d",&map[i][j]);
if(map[i][j]==0)x=i,y=j,flag=1,dp[i][j][0]=1,dp[i][j][1]=1;
int t = map[i][j];
while(t && t%2==0)dp[i][j][0]+=1,t/=2;.
while(t && t%5==0)dp[i][j][1]+=1,t/=5;
}

for(int i = 1;i<=n;i++)
for(int j = 1;j <=n;j++)
{
if(i-1 >= 1 && j-1 >=1)
{
dp[i][j][0]+=min(dp[i-1][j][0],dp[i][j-1][0]);
dp[i][j][1]+=min(dp[i][j-1][1],dp[i-1][j][1]);
}
else if(i-1>=1)
{
dp[i][j][0]+=dp[i-1][j][0];
dp[i][j][1]+=dp[i-1][j][1];
}
else if(j-1>=1)
{
dp[i][j][0]+=dp[i][j-1][0];
dp[i][j][1]+=dp[i][j-1][1];
}
}
int ans = dp[n][n][0]>dp[n][n][1]? 1 : 0;
int cnt = min(dp[n][n][0],dp[n][n][1]);
if(flag && cnt >= 1)
{
printf("1\n");
for(int i=1;i <= x-1;i++)
printf("D");
for(int i=1;i<=y-1;i++)
printf("R");
for(int i=x+1;i<=n;i++)
printf("D");
for(int i=y+1;i<=n;i++)
printf("R");
}
else
{
printf("%d\n",cnt);
int a = n,b = n;
int t = 0;
while(a > 1 && b > 1)
{
if(dp[a-1][b][ans] < dp[a][b-1][ans])
ways[t++]='D',a--;
else
ways[t++]='R',b--;
}
if(b != 1)
for(int i = 1; i<=b-1;i++)
ways[t++]='R';
if(a!=1)
for(int i= 1;i<=a-1;i++)
ways[t++]='D';
for(int i = t-1;i>=0;i--)
printf("%c",ways[i]);
}
return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值