https://acm.zzuli.edu.cn/zzuliacm/problem.php?id=1430
1430: 多少个0
Time Limit: 1 Sec Memory Limit: 128 MB
Submit: 322 Solved: 82
Description
一个n*n的方格,每个格子中间有一个数字是2或者5,现在从方格的左上角走到右下角,每次只能选择向下或者向右移动一格两种移动方式,让所有经过的格子中的数字相乘,求使最后的结果中末尾处0的数字最少。
Input
第一行是一个正整数n(0<n<100)。
接下来n行是一个n*n的矩阵。
Output
一个正整数m,表示最后的结果末尾处最少有m个0。
Sample Input
4
2 5 2 5
5 2 5 2
2 5 5 5
2 2 2 2
Sample Output
1
欸一开始都没看完题就开始bfs真是醉了,后来写了个dp一直WA,自己写的数据都能过,后来看题解说格子数固定的恍然大悟!
本来就是想两个dp出2,5的最大个数,但是苦于不知道如何计算一共走个几个格子无法下手,看完之后发现是啊,题目说了只能向下或者向右走,
从左上角到右下角的话必然横着走n个竖着走n个经过的格子就是(n*2-1)个,这样就好办了!
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define CIN(a) scanf("%d",&a)
#define COUT(a) printf("%d\n",a)
#define ql(a) memset(a,0,sizeof(a))
#define FOR(i,a,b) for(i=a;i<=b;++i)
int main()
{
int dp5[105][105],dp2[105][105],e[105][105];
int n,m,i,j,maxn;
while(CIN(n)!=EOF){ql(dp2),ql(dp5);
maxn=0;int k1,k2;
FOR(i,1,n)
FOR(j,1,n) CIN(e[i][j]);
FOR(i,1,n)
FOR(j,1,n){int c=0;
if(e[i][j]==2) ++c;
dp2[i][j]=max(dp2[i-1][j],dp2[i][j-1])+c;
}k1=min(dp2[n][n],n*2-1-dp2[n][n]);
FOR(i,1,n)
FOR(j,1,n){int c=0;
if(e[i][j]==5) ++c;
dp5[i][j]=max(dp5[i-1][j],dp5[i][j-1])+c;
}k2=min(dp5[n][n],n*2-1-dp5[n][n]);
COUT(min(k1,k2));
}
return 0;
}