UVA136 Ugly Numbers
链接:https://cn.vjudge.net/problem/UVA-136
优先队列是一种抽象数据结构(Abstract Data Type, ADT),行为有些想队列,但先出队列的元素不是先进队列的元素,而是队列中优先级最高的元素,这样就可以允许类似于”急病病人插队“这样的事情发生。
STL的优先队列也定义在头文件<queue>里,用”priority_queue<int> pq“来声明。这个pq是一个”越小的整数优先级越低的优先队列“。由于出对元素并不是最先进队的元素,出对的方法由queue的front()变为了top()。
自定义类型也可以组成优先队列,但必须为每个元素定义一个优先级。这个优先级并不需要一个确定的数字,只需要能比较大小即可。看到这里,是不是想起了sort?没错,只要元素定义了”小于“运算符,就可以使用优先队列。在一些特殊的情况下,需要使用自定义方式比较优先级,例如,要实现一个“个位数大的整数优先级反而小”的优先队列,可以定义一个结构体cmp,重载“()”运算符,使其“看上去”像一个函数,然后用“priority_queue<int,vector<int>,cmp>pq”的方式定义。下面是这个cmp的定义:
struct cmp { bool operator() (const int a,const int b) const//a的优先级比b小时返回true { return a%10>b%10; } };
对于一些常见的优先队列,STL提供了更为简单的定义方法,例如,“越小的整数优先级越大的优先队列”可以写成”priority_queue<int,vector<int>,greater<int>>pq“。注意,最后两个”>“符号不要写在一起,否则会被很多(但不是所有)编译器误以为是”>>“运算符。
STL的queue头文件提供了优先队列,用”priority_queue<int> s“方式定义,用push()和pop()进行元素的入队和出队操作,top()取队首元素(但不删除)。
本题的实现方法有很多,这里仅提供一种,即从小到大生成各个丑数。最小的丑数是1,而对于已生成的丑数,每次取出最小的丑数,生成3个新的丑数。唯一需要注意的是,同一个丑数有多种的生成方式,所以需要判断一个丑数是否已经生成过。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #include <vector> #include <queue> #include <set> using namespace std; typedef long long LL; const int coeff[3]={2,3,5}; int main() { priority_queue<LL, vector<LL>, greater<LL> >pq; set<LL> s; pq.push(1); s.insert(1); for(int i=1;;i++) { LL x=pq.top();pq.pop(); if(i==1500) { cout<<"The 1500'th ugly number is "<<x<<".\n"; break; } for(int j=0;j<3;j++) { LL x2=x*coeff[j]; if(!s.count(x2)) { s.insert(x2); pq.push(x2); } } } return 0; }
这里再写一种方法,不需要判断丑数是否已经生成,每次知生成最小的那个丑数,直到渣到1500个就可以。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <iostream> #define maxn 100005 using namespace std; int cmp(int a,int b,int c) { if(a<b) { if(a<c) return a; else return c; } else { if(b<c) return b; else return c; } return c; } int ugly(int n) { int a[maxn]={0,1}; if(n<=1) return a[n]; int cnt=2; while(1) { int c2=0,c3=0,c5=0; for(int i=1;i<cnt;i++) { if(a[i]*2>a[cnt-1]) { c2=a[i]*2; break; } } for(int i=1;i<cnt;i++) { if(a[i]*3>a[cnt-1]) { c3=a[i]*3; break; } } for(int i=1;i<cnt;i++) { if(a[i]*5>a[cnt-1]) { c5=a[i]*5; break; } } a[cnt++]=cmp(c2,c3,c5); if(cnt>n) return a[n]; } } int main() { int n; cout<<"The 1500'th ugly number is "<<ugly(1500)<<".\n"; return 0; }