Yet Another Multiple Problem ( BFS还原 被除数(倍数))

题目链接

题目: uva 1653

题目大意: 给出一个数字n,和m个数字
要求求出在不含有 这m个数字的情况下,n的最小倍数 !

思路
利用BFS 算法,模拟除法操作,还原出相应的倍数!

大致操作

起初在 BFS队列中 推入一个0,表示除法操作中的一次余数

根据模拟除法操作,余数会*10 + 被除数下一位的数字(0-9枚举) 组成一个新的被除数

然后新被除数 % n 得到新余数
当新余数为0时,代表 我们枚举的数字组成了 n的倍数
即为答案

如图

先用 8%7 会得到余数 1

余数 1会 *10 然后 加上 8 的下一位数字(0) 组成一个新的被除数 10
请添加图片描述

枚举答案
我们通过枚举 0-9的十个数字 一位一位的构建 n的倍数
当然不能 使用那些被禁止的数字
并且当余数为0时且枚举到0时 这种情况应该直接跳过
因为如果枚举到0,且余数为0,下一次余数一定是0,我们不能选择0
当作答案,所以这种情况应当直接跳过!

通过枚举 0-9数字,一位一位的 对 被除数进行 补充
因为我们要寻找最小的倍数,所以一旦再次出现 余数为0的情况,代表这就是n的最小倍数
即为找到答案,退出 BFS,然后输出答案!

剪枝细节
用vis数组进行剪枝,防止计算重复的情况,对每一次余数进行标记
如果出现重复,则直接跳过!

当余数重复时,就是重复的情况
例如 11%7=4, 18%7=4,由于我们的最终目标是得到余数0
那么再接下来的计算中 被除数=4*10+ 接下来我们要枚举的数字
二者的被除数是完全相同的,所以接下来对于我们计算出的余数过程也是完全一致的,所以就需要用vis对所有的余数进行标记,防止重复计算相同情况!

记录答案与输出答案
用text 数组记录到达这个余数所枚举的相应的数字
(text数组记录的就是答案的每一位)

用pre数组记录到达这个余数的上一个余数

text[yushu]=i;
pre[yushu]=cur;

这样我们就可以通过 逆向递推的方式 将答案构建出来!

由于最后一次余数一定为0
第一次的余数也为0

所以有如下推理

int p=0;(最后一次的余数)

while()
{
ans[k++]=text[p];(记录答案)
p=pre[p];(寻找上一个余数)
}

当p再一次为0时,跳出循环,反向输出ans数组即可!

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+5;
bool vis[N];
bool ban[N];
int pre[N];
int text[N];
int n,m;

bool bfs()
{
	queue<int> Q;
	Q.push(0); 
	
	int cur;
	while(Q.size())
	{
		cur=Q.front();
		Q.pop();
		
		//cout<<cur<<endl;
		for(int i=0;i<=9;i++)
		{
			if(ban[i]==1||(cur==0&&i==0))
			{
				continue;
			}
			
			//如果这个数字不被禁止! 
			int yushu=(cur*10+i)%n; // //模拟除法!!!!   /// 
			
			if(vis[yushu]==1)
			continue;
			
			text[yushu]=i;//2  //8 
			pre[yushu]=cur;//0  //2; 
			vis[yushu]=1;
			
			Q.push(yushu);
			if(yushu==0)
			return 1;
		} 
	}
	return 0;
}
void print()
{
	int p=0,k=0;
	int ans[N];
	
	while(p!=0||k==0)
	{
		ans[k++]=text[p];//text[0]=8,   text[2]=2,   28
		p=pre[p];// p=pre[0]=2 , p=pre[2]=0;
	}
	
	for(int i=k-1;i>=0;i--)  //倒序输出// 82 即为 28!!!!!! 
	cout<<ans[i];
	
	cout<<endl;
}
int main()
{
	int kase=1;
	while(cin>>n>>m)
	{
		memset(vis,0,sizeof(vis));
		memset(ban,0,sizeof(ban));
		
		for(int i=1;i<=m;i++)
		{
			int x;
			cin>>x;
			  
			ban[x]=1;
		}
		
		printf("Case %d: ",kase++);
		if(bfs()==0)
		   printf("-1\n");
		else
		   print();
	}
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值