a program that, given a natural number N between 0 and 4999 (inclusively), and M distinct decimal digits X1,X2..XM (at least one), finds the smallest strictly positive multiple of N that has no other digits besides X1,X2..XM (if such a multiple exists).
The input file has several data sets separated by an empty line, each data set having the following format:
On the first line - the number N
On the second line - the number M
On the following M lines - the digits X1,X2..XM.
For each data set, the program should write to standard output on a single line the multiple, if such a multiple exists, and 0 otherwise.
An example of input and output:
Input
22
3
7
0
1
2
1
1
Output
110
0
Source: Southeastern Europe 2000
由题意可知,M个不同的数字可重复选择,属于可重复的全排列问题。本题只要一个最优解,最合适的方法是分支界限算法(回溯法适合多个可行解),分支界限算法在搜索过程中通过限界,可以中途停止对某些不可能得到最优解的子空间进一步搜索(类似于人工智能中的剪枝),故它比穷举法效率更高。分支界限算法有两种实现:FIFO式(队列式),优先队列式。下述代码采用队列式。
AC代码:
#include <bits/stdc++.h>
using namespace std;
int n, m;
int a[11];
void bfs()
{
int y[11];//保存组成的数字
int used[5001];
int q[5001][3];
//入队列
int head = 0;
int tail = 0;
q[head][0] = q[head][1] = q[head][2] = 0;
memset(used, 0, sizeof(used));
while (head <= tail)
{
for (int i=0; i<m; i++)
{
if (head == 0 && a[i] == 0) continue;//数字0不能作为数字的第一位
int x = (q[head][0] * 10 + a[i]) % n;
if (!used[x])
{
//加入队列
tail++;
q[tail][0] = x;//保存余数
q[tail][1] = a[i];//保存数字
q[tail][2] = head;//保存前缀
used[x] = 1;
if (x==0)//余数为零,找到满足条件的了
{
int num = 0;
int k = tail;
while (1)
{
num++;
y[num] = q[k][1];//取出数字
k = q[k][2];//取出前缀
if (k == 0) break;
}
for (int j = num; j >= 1; j--)
printf("%d", y[j]);
printf("\n");
return;
}
}
}
head++;
}
printf("0\n");
}
int main()
{
int i;
while(scanf("%d %d", &n, &m) != EOF)
{
for (i = 0; i < m; i++)
scanf("%d", &a[i]);
sort(a,a+m);//排序后,确保搜索出来的是最小满足条件的
if (n == 0) printf("0\n");
else bfs();
}
return 0;
}