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
题意描述:
给出一个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
相关文章推荐
- Codeforces 2B. The least round way(动态规划)
- Codeforces 2B The least round way
- codeforces 2B The least round way(DP+数学)
- Codeforces 2B The least round way
- codeforces 2B The least round way DP因子路径
- CodeForces 2B The least round way
- codeforces 2B.The least round way(数学&dp)
- CodeForces 2B The least round way(dp+数学)
- [codeforces] 2B - The least round way
- 最小较小codeforces 2B The least round way
- codeforces 2B The least round way
- Codeforces 2B. The least round way
- codeforces 2B The least round way
- codeforces 2B The least round way
- codefroces 2B The least round way
- CF 2B The least round way(DP)
- 2B The least round way
- 【Codeforces Beta Round 2B】【贪心 DP】The least round way 从(1,1)走到(n,n)乘积尾数0尽可能少
- CF_2B_TheLeastRoundWay
- codeforces 2B B. The least round way(dp+数论)