hdu5339-Untitled // BestCoder Round #49 ($) 1001 (搜索)

本文深入探讨了一道编程题目,通过BFS、DFS与DP三种算法解决过程,展示了算法选择的重要性与问题求解的策略。从简单思路入手,逐步深入理解不同算法的特点与适用场景,强调了理清思路与高效代码实现的必要性。

原链接:http://acm.hdu.edu.cn/showproblem.php?pid=5339

题意:给n个数bi,从中取r个,使得a依次对它们取余的结果为零,问r最小是多少。

ps: 比赛的时候觉得第一题多少应该是个简单题,就想着模拟一下,就一直在找规律,就一直想着怎么变成0,最后还是觉得得用bfs,但又觉得第一题这么做是不是有些麻烦,因为五分钟左右好几个人都做出来了,但是别的又想不出,就先这么做了。结果并没有特别想明白就下手了,导致一个简单的思路写了一个多小时。。唉,还是要理清思路再下手啊。。

思路:

<1> bfs 将a赋给结果res,接下来用每次的结果再对所有bi取余,直到结果为零时跳出,返回步骤次数,否则返回-1,即为结果。

<pre class="cpp" name="code">#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <algorithm>
#include <cstring>
#include <utility>
#define ll long long
#define INF 0x3f3f3f3f

using namespace std;

int n,a,b[25],bb[25];

struct node
{
	int x;
	int step;
};

int bfs()
{
	queue<node> que;
	node s;
	s.x=a;
	s.step=0;
	que.push(s);

	while(que.size())
	{
		node temp=que.front();
		que.pop();
		if(temp.x==0) return temp.step;

		node tep=temp;
		for(int i=0;i<n;i++)
		{
			tep.x=temp.x%b[i];
			if(tep.x==temp.x) continue;//重点! 1.排除重复项(也避免了死循环)  2.顺便剪枝
			tep.step=temp.step+1;
			que.push(tep);
		}
	}
	return -1;
}

int main()
{
	int t,res;
	cin>>t;
	while(t--)
	{
		cin>>n>>a;
		for(int i=0;i<n;i++) scanf("%d",&b[i]);
		res=bfs();
		printf("%d\n",res);
	}
	return 0;
}

 

其实后来想想bfs还是很合情合理的,毕竟算是求最短路径。不过后来看了各位大神的代码,发现都和我不一样。。大多数人选择了dfs。

他们都抓住了一个特点,取余时,余数永远小于除数,所以取出的b序列必定是递减的。

<2> dfs

#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <algorithm>
#include <cstring>
#include <utility>
#define ll long long
#define INF 0x3f3f3f3f

using namespace std;

int ans,b[22];

void dfs(int i,int res,int c) //i 剩余b个数;res 计算结果;c 次数;
{
    if(c>=ans) return ; //最先判断,剪枝

    if(res==0)
    {
        ans=c; //保证了 c>=ans,保留结果
        return ;
    }

    if(i==0) return ;

    dfs(i-1,res,c);
    dfs(i-1,res%b[i],c+1);
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        int n,a;
        scanf("%d%d",&n,&a);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&b[i]);
        }

        sort(b+1,b+1+n);

        ans=INF; //赋极大值,但我总觉得这个不保险,如果数据特别大的时候=.=
        dfs(n,a,0);

        if(ans==INF)ans=-1;
        printf("%d\n",ans);
    }
    return 0;
}


<3>然后惊奇的又发现了dp..dp的思维渣渣的大脑真的不敢恭维- -

#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <algorithm>
#include <cstring>
#include <utility>
#define ll long long
#define INF 0x3f3f3f3f

using namespace std;

int dp[1000010];
int num[30];

int main()
{
    int T,m,a;
    scanf("%d",&T);
    for(int t=1;t<=T;t++)
    {
        scanf("%d%d",&m,&a);
        for(int i=1;i<=m;i++) scanf("%d",&num[i]);
        for(int i=0;i<=a;i++) dp[i]=1e9;

        dp[a]=0;
        for(int i=a;i>=0;i--) //dp[i]保留结果为i时的最短步数
           if(dp[i]>=0)
           {
               for(int j=1;j<=m;j++)
                  dp[i%num[j]]=min(dp[i%num[j]],dp[i]+1);
           }

        if(dp[0]<1e9)
          printf("%d\n",dp[0]);
        else
          printf("-1\n");
    }
    return 0;
}


看大神们的代码真的可以学到好多!

虽然只是简单的搜索题。


评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值