您的位置:首页 > 其它

Codeforces 2B: The least round way【动态规划】

2017-07-12 15:59 405 查看
原题链接:http://codeforces.com/contest/2/problem/B

题意描述:

给出一个n*n的矩阵,现在要从1,1点走到n,n点,每一步只能朝下或者朝右走

在走的过程中要将经过的数字累乘起来,你希望当你走到n,n点的时候累乘的结果的末尾0的数量尽可能的少

输出这个数量和一个行走方案

思路:

矩阵中的数a[i][j]可以拆分为C*2^x*5^y的结构,则他所包含的末尾0数量为min(x,y),而累乘就是x,y的累加

首先对于矩阵中的每一个a[i][j],预处理出x与y的数量,接着分别对x与y进行动态规划

转移方程:

dp(i,j) = min(dp(i-1,j),dp(i,j-1)) + value(i,j)

则答案就为x和y中dp

的较小值

接下来求一条路径,我们在dp的过程中可以对2和5这两种情况分别保存路径,接着再根据dp

的较小值决定输出2的路径还是5的路径

AC代码

#include <bits/stdc++.h>
#define INF 0x7fffffff
using namespace std;

int board[1005][1005];
int save[1005][1005][2];
char path[1005][1005][2];
int two[1005][1005],five[1005][1005];

int get2(int n){
if(n==0) return 1;
int ret=0;
while(n%2==0){
ret++;
n/=2;
}
return ret;
}

int get5(int n){
if(n==0) return 1;
int ret=0;
while(n%5==0){
ret++;
n/=5;
}
return ret;
}

int dp(int x,int y,int z){
if(save[x][y][z]>=0)
return save[x][y][z];

int up=INF,left=INF;
if(x>1) up=dp(x-1,y,z);
if(y>1) left=dp(x,y-1,z);
if(z==0){
save[x][y][z] = min(up,left)+two[x][y];
}else{
save[x][y][z] = min(up,left)+five[x][y];
}
path[x][y][z] = up<left?'D':'R';
return save[x][y][z];
}

int main(){
ios::sync_with_stdio(false);
memset(save,-1,sizeof(save));
int n,posx0,posy0;
bool haszero = false;
string ans;
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
cin>>board[i][j];
if(board[i][j]==0){
haszero = true;
posx0 = i;
posy0 = j;
}
two[i][j] = get2(board[i][j]);
five[i][j] = get5(board[i][j]);
}

save[1][1][0] = two[1][1];
save[1][1][1] = five[1][1];
dp(n,n,0); dp(n,n,1);

int out = min(save

[0],save

[1]);
if(!haszero || out<=1){
cout<<out<<endl;
int x=n,y=n;
int z = save

[0]<save

[1]?0:1;
while(x!=1||y!=1){
ans.push_back(path[x][y][z]);
if(path[x][y][z]=='D') x--;
else y--;
}
reverse(ans.begin(),ans.end());
cout<<ans<<endl;
}else{
cout<<1<<endl;
for(int i=1;i<posx0;i++) ans.push_back('D');
for(int i=1;i<posy0;i++) ans.push_back('R');
for(int i=posx0+1;i<=n;i++) ans.push_back('D');
for(int i=posy0+1;i<=n;i++) ans.push_back('R');
cout<<ans<<endl;
}

return 0;
}

总结:
这道题在最后求路径的时候一直出错,原先的想法是整个dp计算完毕之后从n,n出发反向找到1,1获得一条路径,因为dp的结果是从上侧和左侧累加更新的,所以一定存在这样一条路径,但是在判断的时候不清晰,少加了一项对应点的value导致原本从左侧更新来的点我误认为是从上侧,进而疯狂WA
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: