(HDU1664)Different Digits-BFS-余数判重

本文针对问题DifferentDigits提供了详细的算法解答,介绍了如何通过枚举和广度优先搜索寻找一个正整数m,使得m为给定正整数n的倍数且m在十进制表示下包含尽可能少的不同数字。文章探讨了利用余数判重和鸽笼原理来优化搜索过程,以减少不必要的计算。

Different Digits

Time Limit: 10000/4000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1789    Accepted Submission(s): 541


 

Problem Description

Given a positive integer n, your task is to find a positive integer m, which is a multiple of n, and that m contains the least number of different digits when represented in decimal. For example, number 1334 contains three different digits 1, 3 and 4.

 

 

Input

The input consists of no more than 50 test cases. Each test case has only one line, which contains a positive integer n ( 1<=n < 65536). There are no blank lines between cases. A line with a single `0' terminates the input.

 

 

Output

For each test case, you should output one line, which contains m. If there are several possible results, you should output the smallest one. Do not output blank lines between cases.

 

 

Sample Input

 

7 15 16 101 0

 

 

Sample Output

 

7 555 16 1111

题目分析:

题目大意就是求一个数能整除n,并且数中包含的不同数字最少。直接的想法就是去枚举每一位的数,但是啥时候停止,题目有没有位数的限制,难道要一直找下去?所以这里就应该想到有个限制条件,限制搜索的深度。题目中说的是找一个数的倍数,这里不难想到用余数判重。还有一个点就是:对于任意的整数 n ,必然存在一个由不多于两个的数来组成的一个倍数。 因为 a ,aa , aaa…… 取 n+1 个,则由鸽笼原理,必有两个模 n 余数相同,相减即得 n 的倍数 m 。而 m 只由 a 、 0 组成。也就是说枚举时可以只枚举一个数的情况和两个数的情况。

代码:https://blog.youkuaiyun.com/driver13/article/details/49287299

#include<iostream>
#include<string.h>
#include<string>
using namespace std;

/*
Node:	d:当前位的数字 val:余数 pre:前一位数字在队列中的位置 cnt:数的位数
a: 保存枚举的数(实际只用到了a[1],a[2],只用a[1]表明求的数只有1个数组成的情况,a[1],a[2]都用表明求的数有两个不同的情况)
ans: 存最终的答案
tans: 存中间求解过程中的答案,不一定是最好的情况
*/


struct Node {
	int d, val, pre;	
	int cnt;
}cur,now,q[65540];
int n;
int vis[65540];
char a[5];
int mcnt, tcnt,h;
string ans, tans;

void getans(int k) {
	char c;
	if (k == -1)return;
	else {
		getans(q[k].pre);
		c = q[k].d + '0';
		tans += c;
	}
}


bool bfs(int k)
{
	int i, j;
	int head = 0, tail = -1;
	memset(vis, 0, sizeof(vis));
	//第一位数的情况
	for (i = 1; i <= k; i++)
	{
		if (a[i])
		{
			cur.cnt = 0;
			cur.d = a[i];
			cur.pre = -1;
			cur.val = a[i] % n;
			vis[cur.val] = 1;
			q[++tail] = cur;
		}
	}
	int nval, ncnt,tval;
	while (head <= tail)
	{
		now = q[head];
		nval = now.val;
		ncnt = now.cnt;
		if (ncnt > mcnt)break;//当前求的数的位数已经大于以求的满足条件的数的位数了就不用在搜了
		if (!nval) 
		{
			h = head;
			tcnt = ncnt;
			return true;
		}
		for (i = 1; i <= k; i++)
		{
			tval = (nval * 10 + a[i]) % n;
			if (!vis[tval])
			{
				vis[tval] = 1;
				cur.cnt = ncnt + 1;
				cur.d = a[i];
				cur.pre = head;
				cur.val = tval;
				q[++tail] = cur;
			}
		}
		head++;
	}
	return false;
}

int main() {
	int flag;
	while (cin >> n&&n) {
		if (n >= 1 && n <= 9) 
		{
			cout << n << endl;
			continue;
		}
		flag = 0;
		ans = "xx";//表示答案没找到
		mcnt = 1000000000;//找到的数的位数
		//枚举一个数的情况
		for (int i = 1; i <= 9; i++)
		{
			a[1] = i;
			if (bfs(1)) {
				tans = "";
				getans(h);
				if (mcnt > tcnt || mcnt == tcnt&&ans > tans)
				{
					ans = tans;
					mcnt = tcnt;
				}
			}
		}
		if (ans != "xx") {
			flag = 1;
			cout << ans << endl;
		}
		if (flag)continue;
		//枚举两个数的情况
		for (int i = 0; i <= 9; i++)
		{
			a[1] = i;
			for (int j = i + 1; j <= 9; j++)
			{
				a[2] = j;
				if (bfs(2))
				{
					tans = "";
					getans(h);
					if (mcnt > tcnt || mcnt == tcnt&&ans > tans)
					{
						ans = tans;
						mcnt = tcnt;
					}
				}
			}
		}
		cout << ans << endl;
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值