原题: http://poj.org/problem?id=1189
//关键在于输入的处理以及运算过程中的 约分,约分可以保证每一次计算的结果都在long long的范围内,否则爆了会导致错误的结果 //定义结构体,并重载+和/运算符 //转移方程:如果字符是'*',则dp[i+1][c]=dp[i+1][c]+dp[i][c]/2;dp[i+1][c+1]=dp[i+1][c+1]+dp[i][c]/2; // 如果字符是'.',则dp[i+2][c+1]=dp[i+2][c+1]+dp[i][c]; //这题一直是WA,就是没有及时地约分,导致数值超出了Longlong的范围,注意每一次计算后都约分就可以了。 //PS:long long的范围:-9223372036854775808 ~ 9223372036854775807 #include<cstdio> #include<memory.h> typedef long long ll; ll gcd(ll a,ll b) { if(b==0)return a; return gcd(b,a%b); } struct F //分数结构体 { ll fz; ll fm; }; F operator + (F a,F b)//重载+ { if(a.fz==0)return b; if(b.fz==0)return a; F tmp; if(a.fm==b.fm) { tmp.fm=a.fm; tmp.fz=a.fz+b.fz; }else if(a.fm<b.fm){ tmp.fm=b.fm; tmp.fz=a.fz*b.fm/a.fm+b.fz; }else{ tmp.fm=a.fm; tmp.fz=b.fz*a.fm/b.fm+a.fz; } ll g=gcd(tmp.fm,tmp.fz); //每一次计算都要约分 tmp.fm=tmp.fm/g; tmp.fz=tmp.fz/g; return tmp; } F operator / (F a,ll d) //重载/ { ll g=gcd(a.fz,d);//每一次计算都要约分 a.fz=a.fz/g; d=d/g; a.fm=a.fm*d; return a; } int strlen(char *from) { int i=0; while(from[i]!='\0') { i++; } return i; } int main() { const int size=55; int n,m; while(~scanf("%d %d",&n,&m)) { getchar(); char str[550]; F dp[55][55]; memset(dp,0,sizeof(F)*size*size); // for(int i=0;i<=54;i++) // { // for(int j=0;j<=54;j++) // { // dp[i][j].fm=dp[i][j].fz=0; // } // } dp[1][1].fm=1; dp[1][1].fz=1; for(int i=1;i<=n;i++) { gets(str);//输入n行 int c=1; int len=strlen(str); for(int j=0;j<len && c<=i;j++)//遍历这行的每一个字符 { if(str[j]==' ') { continue; }else if(str[j]=='*'){ //dp dp[i+1][c]=dp[i+1][c]+dp[i][c]/2; dp[i+1][c+1]=dp[i+1][c+1]+dp[i][c]/2; c++; }else if(str[j]=='.'){ dp[i+2][c+1]=dp[i+2][c+1]+dp[i][c]; c++; } } } if(dp[n+1][m+1].fz==0) { printf("0/1\n"); continue; }else{ printf("%lld/%lld\n",dp[n+1][m+1].fz,dp[n+1][m+1].fm); } } return 0; }