转一篇好文:poj1338 poj2591 poj2545 这三道题

简介:

poj1338 poj2591 poj2545 这三道题


先来看1338

题目定义一种集合,使得其中的元素的素数因子只能是2,3,5

即:1, 2, 3, 4, 5, 6, 8, 9, 10, 12, ...

要求这个集合的第n个数是多少

很直接的想法,我们通过题目的要求预处理算出这样的集合,然后再输出第n个数

当然,我们在得到这样的一个数组num[]时,必须是从小到大的,其实这也是关键所在

这个集合是通过集合里的每一个数 × 2,× 3,× 5来扩展的,要想从小到大,从num[1]开始扩展时,由于× 2,× 3,× 5大小不同,所以num[]的下一个元素是这三个数的最小值。所以到下次时,2是在乘以新的元素,而3,5还在乘原来的元素,但这三个数比较后最小的继续添加进集合里。由于有了这样的延迟作用,我们可以设置三个指针p2,p3,p5分别指向2,3,5待乘的数。

要记得处理重复的数,在每扩展一个元素时,判断该数是否能通过其他数来乘得,是的话就右移p

参考自:http://acm.pku.edu.cn/JudgeOnline/showmessage?message_id=113667

代码:

#include<iostream>
using namespace std;
int main(){
 long long ans[1510] = {0,1};
 int p2 = 1,p3 = 1,p5 = 1;
 for(int i =2;i<=1500;i++){
  ans[i] = min(ans[p2]*2,min(ans[p3]*3,ans[p5]*5));
  //他们乘时有延迟,不同数有先乘后乘,但各自的p指向他们下次要乘的数
  if(ans[i]==2*ans[p2])p2++;
  if(ans[i]==3*ans[p3])p3++;
  if(ans[i]==5*ans[p5])p5++;
 }
 int n;
 while(cin>>n,n)cout<<ans[n]<<endl;
 return 0;
}
现在来看poj2591,只是定义集合的方式不同了而已:
Set S is defined as follows: 
(1) 1 is in S; 
(2) If x is in S, then 2x + 1 and 3x + 1 are also in S; 
(3) No other element belongs to S. 
代码
#include<iostream>
using namespace std;
int ans[10000010] = {0,1};
int main(){
 int p2 = 1,p3 = 1;
 for(int i =2;i<=10000000;i++){
  ans[i] = min(ans[p2]*2+1,ans[p3]*3+1);
  if(ans[i]==2*ans[p2]+1)p2++;
  if(ans[i]==3*ans[p3]+1)p3++;
 }
 int n;
 while(cin>>n)cout<<ans[n]<<endl;
 return 0;
}
poj2545
#include<iostream>
using namespace std;
long long num[1000000],a,b,c,pa,pb,pc,n;
int main()
{
    cin>>a>>b>>c>>n;
    num[0] = 1;
    pa=pb=pc =0;
    for (int i =1;i<=n;i++)
    {
        num[i] = min(num[pa]*a,min(num[pb]*b,num[pc]*c));
        if (num[i]==num[pa]*a)pa++;
        if (num[i]==num[pb]*b)pb++;
        if (num[i]==num[pc]*c)pc++;
    }
    cout<<num[n]<<endl;
return 0;
}
只要记住那加亮的核心代码就行了,就可以用来按照已给表达式来扩展集合,
主要是设置指针来使元素从小到大,且不重复!
附:poj1338用优先级队列和set实现的版本:
#include<iostream>
#include<queue>
using namespace std;

typedef pair<long long,int> node;//要用long long
int main(){
 vector<long long>ans;
 priority_queue<node,vector<node>,greater<node> > que;//最小堆
 que.push(make_pair(1,2));
 for(int i =1;i<=1500;i++){
    node top = que.top();//每次选最小的作为下一次的被乘数
    que.pop();
  //注意这里每个case后面没有break,这样处理可以避免重复的插入
  switch(top.second){//乘的时候是乘上一次乘时的质数开始,这样从小到大乘就不会重复了,不然大的又回去乘2
   case 2:que.push(make_pair(top.first*2,2));
   case 3:que.push(make_pair(top.first*3,3));
   case 5:que.push(make_pair(top.first*5,5));
    }
    ans.push_back(top.first);//将最小的数加入容器,以后这个容器才是从小到大的
 }
 int n;
 while(cin>>n,n)cout<<ans[n-1]<<endl;
 return 0;
}
#include<iostream>
#include<set>
using namespace std;
int main(){
 long long ans[1510];
 set<long long>se;
 se.insert(1);
 for(int i =1;i<=1500;i++){//set会自动处理重复的数!
    ans[i] = *se.begin();
    se.erase(se.begin());
    se.insert(ans[i]*2);
    se.insert(ans[i]*3);
    se.insert(ans[i]*5); 
 }
 int n;
 while(cin>>n,n)cout<<ans[n]<<endl;
 return 0;
}

相关文章
|
7月前
|
算法
Highways(POJ—2485)
Highways(POJ—2485)
|
人工智能 算法 BI
poj 2192 Zipper
题目链接:http://poj.org/problem?id=2192 Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 18658   Accepted: 6651 Description Given ...
977 0
|
并行计算 网络架构
poj-1005-l tanink i need a houseboat
Description Fred Mapper is considering purchasing some land in Louisiana to build his house on. In the process of investigating the land, he learned ...
988 0
|
算法 数据建模 机器学习/深度学习
poj1273Drainage Ditches
1 #include 2 /* 3 题意:就是寻找从源点到汇点的最大流! 4 要注意的是每两个点的流量可能有多个,也就是说有重边,所以要把两个点的所有的流量都加起来 5 就是这两个点之间的流量了! 6 ...
853 0
|
机器学习/深度学习