oj1026: 丑数(优先队列以及寻找最优解)

题目要求
丑数就是这个数的质因子只有2,3,5,7这四个,除此之外不再含有其它
别的质因子。

注意1也被认为是丑数.丑数的前20个为
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 24, 25, 27, … ;
Input
每行输入一个N,1 <= N <= 5842,N为0时输入结束.
Output
输出相应的第N个丑数.
Sample Input
Raw
1
2
3
4
11
12
13
21
22
23
100
1000
5842
0
Sample Output
Raw
1
2
3
4
12
14
15
28
30
32
450
385875
2000000000
这道题在以前,只会常规遍历寻找数字是否整除等于0时,总是显示超时。最近看到了vector,set,map以及优先队列又想起来了。
第一遍做的时候很单纯,丑数是2,3,5,7的倍数,只要从最小的丑数1开始,用一个优先队列保持所有已生成的丑数,每次取出最小的那个数字让它乘上2,3,5,7自然可以得到下一个丑数,因为是优先队列,可以使它从小到大直接排列,要注意的使这样做会出现重复数字,所以要记得去重。最后只要知道所给数字,即可知道该位置上的丑数了。
完整代码

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<algorithm>
#include<queue>
#include<math.h>
#include<set>
#include<queue>

using namespace std;
typedef long long LL;
const int num[4]={2,3,5,7};

int main()
{
  priority_queue<LL,vector<LL>,greater<LL> >pq;//从小到大的优先队列
  set<LL>s;//set
  int n=1,t;
  int a[5844];
  pq.push(1);//插入刚开始的1
  s.insert(1);
  for(int i=1; ;i++)
  {
    LL x=pq.top();pq.pop();
    if(i==n)
    {
      a[n]=x;
      n++;
      if(n==5843)
        break;
    }
    for(int j=0;j<4;j++)
    {
      LL x2=x*num[j];
      if(!s.count(x2))
      {
        s.insert(x2);
        pq.push(x2);//不断更新队列
      }
    }
  }
  while(cin>>t)
  {
    if(t==0)break;
     cout<<a[t]<<endl;
  }
	return 0;
}

后来问学长关于队列的相关知识,他说我这做复杂了。。。
可以利用寻找最优解的思想,第一个确定ans[1]=1,现在有2,3,5,7四种方式指向ans[1],这里肯定会选择2。以此类推可以确定第二个,第三个。。。。
这里贴部分代码

inline void init()
{
    ans[1] = 1;
    fill(p, p + 4, 1);//置1
    ll val;
    for(int i=2; i<=maxN; i++)
    {
        val = MIN_4(ans[p[0]] * 2LL, ans[p[1]] * 3LL, ans[p[2]] * 5LL, ans[p[3]] * 7LL);
        if(val == ans[p[0]] * 2LL) p[0]++;
        if(val == ans[p[1]] * 3LL) p[1]++;
        if(val == ans[p[2]] * 5LL) p[2]++;
        if(val == ans[p[3]] * 7LL) p[3]++;
        ans[i] = val;
    }
}
发布了38 篇原创文章 · 获赞 27 · 访问量 3170

猜你喜欢

转载自blog.csdn.net/qq_45891413/article/details/105188027
今日推荐