B - The least round way
link
题意:给定n×n方正,从右上角出发走到左下角,要求所有经过路径得到的数乘积中0的个数最少。
输出最小数、还原路径
碎碎念:一开始写的转移方程判断条件是判断2、5与当前的个数相加后取最小值,判断哪个小走哪个。假的。正解应该一直对2和5一直取最小的,在最后再取最小值。手推一下就okk
零的个数就是所有乘数中2的个数和5的个数的最小值
注意如果路径中存在0,要做特殊标记。含有0可以使答案恒为1
递归思想还原路径,注意输出在递归后,这样才是从头开始走
wa了好多test29,记得把边界的最大值设置为maxn×maxn不是maxn
int n;
struct node{
int tw,fi;
}dp[maxn][maxn],mp[maxn][maxn];
void way1(int x,int y){
if(x==1&&y==1)
return;
if(x==1){
for(int i=1;i<y;i++)
cout<<"R";
return;
}
if(y==1){
for(int i=1;i<x;i++)
cout<<"D";
return;
}
if(dp[x][y].tw-mp[x][y].tw==dp[x-1][y].tw){
way1(x-1,y);
cout<<"D";
}
else{
way1(x,y-1);
cout<<"R";
}
}
void way2(int x,int y){
if(x==1&&y==1)
return;
if(x==1){
for(int i=1;i<y;i++)
cout<<"R";
return;
}
if(y==1){
for(int i=1;i<x;i++)
cout<<"D";
return;
}
if(dp[x][y].fi-mp[x][y].fi==dp[x-1][y].fi){
way2(x-1,y);
cout<<"D";
}
else{
way2(x,y-1);
cout<<"R";
}
}
int main(){
n=ird();
for(int i=0;i<=n+1;i++){//边界条件设置
dp[i][0].tw=maxn*maxn;
dp[0][i].tw=maxn*maxn;
dp[i][0].fi=maxn*maxn;
dp[0][i].fi=maxn*maxn;
}
int f=0,xx,yy;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
int t=ird();
if(t==0){
f=1;
xx=i;
yy=j;
continue;
}
while(t%2==0){
mp[i][j].tw++;
t/=2;
}
while(t%5==0){
mp[i][j].fi++;
t/=5;
}
if(i==1&&j==1){
dp[i][j].tw+=mp[i][j].tw;
dp[i][j].fi+=mp[i][j].fi;
continue;
}
dp[i][j].fi=min(dp[i][j-1].fi,dp[i-1][j].fi)+mp[i][j].fi;
dp[i][j].tw=min(dp[i][j-1].tw,dp[i-1][j].tw)+mp[i][j].tw;
}
}
if(min(dp[n][n].tw,dp[n][n].fi)==0||f==0){
cout<<min(dp[n][n].tw,dp[n][n].fi)<<endl;
if(dp[n][n].tw<dp[n][n].fi){
way1(n,n);//2的个数是限制条件
}
else way2(n,n);//5的个数是限制条件
cout<<endl;
}
else{//路径中有0的情况,并且没有一条路径可以不含0的情况
cout<<1<<endl;
for(int i=1;i<xx;i++) cout<<"D";
for(int i=1;i<yy;i++) cout<<"R";
for(int i=xx;i<n;i++) cout<<"D";
for(int i=yy;i<n;i++) cout<<"R";
cout<<endl;
}
return 0;
}