poj1189 钉子和小球

原题: 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;
}


猜你喜欢

转载自blog.csdn.net/zark721/article/details/77769310