【USACO-Chapter1-1.3】【模拟】Prime Cryptarithm

【题目描述】

下面是一个乘法竖式,如果用我们给定的那n个数字来取代*,可以使式子成立的话,我们就叫这个式子牛式。

        * * *
    x     * *
   ----------
        * * *
      * * *
   ----------
      * * * *

数字只能取代*,当然第一位不能为0,况且给定的数字里不包括0。

注意一下在美国的学校中教的“部分乘积”,第一部分乘积是第二个数的个位和第一个数的积,第二部分乘积是第二个数的十位和第一个数的乘积.

写一个程序找出所有的牛式。

【输入格式】(crypt1.in)

Line 1:数字的个数n。

Line 2:N个用空格分开的数字(每个数字都属于{1,2,3,4,5,6,7,8,9})。

【输出格式】(calffac.out)

共一行,一个数字。表示牛式的总数。

【输入样例】

5
2 3 4 6 8

【输出样例】

1
【样例分析】
        2 2 2
    x     2 2
   ----------
        4 4 4
      4 4 4
   ----------
      4 8 8 4

注意:结果只能为4位



按照题目要求搜就是了,这道题也可以直接枚举所有可能,但我从觉得那样做不好,所以写了个dfs+判断,可能是最长的代码了吧。。。

代码:

#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 10 + 10;
int m[maxn];
int a[maxn],b[maxn];//1,2,3代表个位,十位,百位(下同)。a是第一行,b是第二行
int t[maxn];//最后结果
int com1[maxn],com2[maxn];//分别表示中间两行
bool sign[maxn];
int n;
int ans = 0;

void init()
{
	freopen("crypt1.in","r",stdin);
	freopen("crypt1.out","w",stdout);
}

void readdata()
{
	memset(sign,false,sizeof(sign));
	scanf("%d",&n);
	for(int i = 1;i <= n;i++)
	{
		scanf("%d",&m[i]);
		sign[m[i]] = true;
	}
}

bool check()
{
	memset(t,0,sizeof(t));
	memset(com1,0,sizeof(com1));
	memset(com2,0,sizeof(com2));
	for(int i = 1;i <= 2;i++)
	  for(int j = 1;j <= 3;j++)
	  {
		  if(i == 1)
		  {
			  com1[j] += b[i] * a[j];
			  while(com1[j] >= 10)
			  {
				  com1[j] -= 10;
				  ++com1[j+1];
			  }
			  if(j == 1)
			  {
				  t[1] = com1[j];
				  if(!sign[t[1]])return false;
			  }
			  if(!sign[com1[j]])return false;
			  if(com1[4] != 0)return false;
		  }
		  if(i == 2)
		  {
			  com2[j] += b[i] * a[j];
			  while(com2[j] >= 10)
			  {
				  com2[j] -= 10;
				  ++com2[j+1];
			  }
			  if(!sign[com2[j]])return false;
			  if(com2[4] != 0)return false;
		  }
	  }
	int i = 2;
	while(i <= 3)
	{
		t[i] += com1[i] + com2[i-1];
		while(t[i] >= 10)
		{
			t[i] -= 10;
			++t[i+1];
		}
		if(!sign[t[i]])return false;
		++i;
	}
	t[4] += com2[3];
	if(t[4] > 10)
	{
		return false;
	}
	else
	{
		if(sign[t[4]])
		{
			return true;
		}
		else
		{
			return false;
		}
	}
	return true;
}

void dfs2(int x)
{
	if(x == 3)
	{
		if(check())
		{
			++ans;
		}
		return;
	}
	for(int i = 1;i <= n;i++)
	{
		b[x] = m[i];
		dfs2(x+1);
		b[x] = 0;
	}
}

void dfs1(int x)
{
	if(x == 4)
	{
		dfs2(1);
		return;
	}
	for(int i = 1;i <= n;i++)
	{
		a[x] = m[i];
		dfs1(x+1);
		a[x] = 0;
	}
}

void solve()
{
	dfs1(1);
	printf("%d\n",ans);
}

int main()
{
	init();
	readdata();
	solve();
	return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值