hdu1226超级密码 bfs

本文介绍了HDU1226题目,强调不应枚举所有可能的十进制数,而应从已给数字出发,通过BFS算法寻找数字组合,判断是否为n的整数倍。利用余数相同的剪枝策略限制队列大小,优化算法效率,并特别指出n=0的情况需特判。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门:hdu1226

中文题题意就不多说了,重点是方法,不要试图去枚举十进制n的倍数来然后看看给的几个数字能否凑出来,可以想象2要翻倍多少次才能达到500位的长度,因此要从给定的数字入手,枚举数字的各种组合情况,判断是不是n的整数倍。而且这样的话还有一个强剪枝就是如果余数相同就没必要再次入队了,因为无论是大数还是小数如果模n同余那么再添上其他数字的话再模n还是同余的,这样每个余数最多在队列里出现一次,也就是说队列中最多出现5000个结点,大大优化了时间。

还有要注意的一点是n=0时的特判。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
int n,c,m,book[20],vis[5005];
int flag=0;
struct node{  //结构体中的数组用来存密码的每一位
	int s[505],len;
};
queue<node> q;
int mod(node t)//取余函数
{
	int temp=0;
	for(int i=0;i<t.len;i++)
	{
		temp=(temp*c+t.s[i])%n;
	}
	return temp;
}
void print(node a)
{
	for(int i=0;i<a.len;i++)
	{
		if(a.s[i]<=9)
		printf("%d",a.s[i]);
		else
		printf("%c",a.s[i]+'A'-10);
	}
	putchar('\n');
	return ;
}
void bfs()
{
	node t;
	t.len=0;
	int v;
	for(int i=1;i<16;i++)//先处理第一个结点,注意这里是从一开始循环,因为密码第一位不能为零
	{
		if(book[i])
		{
			t.s[0]=i;
			t.len=1;
			v=mod(t);
			if(!v)
			{
				print(t);
				flag=1;
				return ;
			}
			else
			{
				if(!vis[v])
				{
					vis[v]=1;
					q.push(t);
				}
			}
		}
	}
		while(!q.empty())
		{
			t=q.front();
			q.pop();
			for(int i=0;i<16;i++)
			{
				if(book[i])
				{
					t.s[t.len]=i;
					t.len++;
					v=mod(t);
					if(!v)
					{
						print(t);
						flag=1;
						return ;
					}
					else
					{
						if(!vis[v]&&t.len<499)//注意这里要判断一下位数再入队
						{
							vis[v]=1;
							q.push(t);
						}
					}
					t.len--;
				}
			}
		}
	return ;
}
int main()
{
	int T;
	char s[2];
	scanf("%d",&T);
	while(T--)
	{
		flag=0;
		memset(vis,0,sizeof(vis));
		memset(book,0,sizeof(book));
		while(!q.empty())
		q.pop();
		scanf("%d%d%d",&n,&c,&m);
		getchar();
		for(int i=0;i<m;i++)
		{
			scanf("%s",s);
			if(s[0]<='9'&&s[0]>='0')
			book[s[0]-'0']=1;
			else
			{
				book[10+s[0]-'A']=1;
			}
		}
		/*for(int i=0;i<16;i++)
		printf("%d",book[i]);*/
		if(n)//n等于0的话不能进行取模操作因此也不能入队,以为0的倍数只有0所以特判一下给没给0这个数字就好了
		{
			bfs();
			if(!flag)
			printf("give me the bomb please\n");
		}
		else
		{
			if(book[0])
			printf("0\n");
			else
			printf("give me the bomb please\n");
		}
	}
return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值