ZOJ 1136 Multiple(分支界限算法)

Multiple

Time Limit: 10 Seconds       Memory Limit: 32768 KB

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


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;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值