Multiple POJ - 1465(同余剪枝)

Multiple

题目链接:POJ - 1465
题意:给出一个十进制数n, 和m个十进制个位数, 找出一个最小的数x, 使得x是n的倍数, 输出n;
一个新知识点: 同余剪枝;
我们先把m个十进制个位数由小到大排序, 当a<b时 若a≡b(mod n),就不再在扩展b(a小所以先扩展了a),
为什么呢, 由于a, b对n同余, 所以(a*10+i)%n ==(b*10+i)%n;, 当b后边加一个i能整除n时, 之前a一定也可以加i 整除n;也可以说之后b扩展出来的一定能由a扩展, 所以不需要再扩展b;(我们要求的是一个最小值!!!)
注意n=0时要特判;
由于最后结果可能是个大数, 所以要找个巧妙地方法存数;具体看代码;
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int INF = 0x3f3f3f3f;
int digit[15], n, m;
struct node{//now表示当前数位上是什么数, pre表示上一数位是什么数, mod表示当前数对n的余数;
	int now, pre, mod;
};
int vis[5100];
vector<node> vec;
vector<int> ans;
void print(int k){
	ans.clear();
	while(k>=0){
		ans.push_back(vec[k].now);
		k=vec[k].pre;
	}
	for(int i=ans.size()-1; i>=0; i--){
		printf("%d", ans[i]);
	}
	printf("\n");
}
void bfs(){
	vec.clear();
	node tmp;
	memset(vis, 0, sizeof(vis));
	for(int i=0; i<m; i++){
		if(digit[i]==0) continue;//不能有前导零;因为0mod任何数都是0;
		tmp.now=digit[i];
		tmp.pre=-1;
		tmp.mod=digit[i]%n;
		vis[tmp.mod]=1;
		vec.push_back(tmp);
	}
	int head=0;
	while(head<vec.size()){
		tmp=vec[head];
		//printf("%d %d %d\n", tmp.now, tmp.mod, tmp.pre);
		if(tmp.mod==0){
			print(head);
			return;
		}
		for(int i=0; i<m; i++){
			int tmod=(tmp.mod*10+digit[i])%n;
			if(vis[tmod]) continue;
			node p;
			p.now=digit[i];
			p.pre=head;
			p.mod=tmod;
			vec.push_back(p);
			vis[tmod]=1;
		}
		head++;
	}
	printf("0\n");
}
int main(){
	while(~scanf("%d%d", &n, &m)){
		for(int i=0; i<m; i++)
			scanf("%d", &digit[i]);
		sort(digit, digit+m);
		if(n==0){
			printf("0\n");
			continue;
		}
		bfs();
	}
	return 0;
}


猜你喜欢

转载自blog.csdn.net/sirius_han/article/details/80230932