1.某年机考
在STL库中,我们已经有了现成的priority_queue可以使用。这里只是对如何实现优先队列做些探索,以快速地生成我们需要的代码。
1.有一道题说,实现这样一个优先队列,满足以下指令:
(1)ADD ID P:添加编号为ID,优先级为P的元素到队列中;
(2)NEXT :输出队列中优先级最高的元素的编号,若存在优先级相同的元素,则输出编号最小的元素;
(3)REMOVE ID:移除队列中编号为ID的元素;
(4)COUNT:输出队列中的元素数目;
(5)SEE:输出队列中的当前元素的编号及优先级。
如果此时限制你不能使用priority_queue,该怎么办呢?
我们采用了现成的数据结构map和set来实现:
#include "stdafx.h"
#include<iostream>
#include<map>
#include<set>
#include<string>
#include<algorithm>
#include<iterator>
using namespace std;
map<int, int>p_queue;
struct compare
{
bool operator()(const int &a, const int&b)const
{
return p_queue[a] > p_queue[b] || (p_queue[a] == p_queue[b] && a < b);
}
};
int main()
{
string orders;
set<int,compare>id_pool;
while (cin >> orders)
{
if (orders[0] == 'A')//add N P
{
int id, prio;
cin >> id >> prio;
p_queue.insert({id,prio});
id_pool.insert(id);
}
else if (orders[0] == 'N')//next
{
if (id_pool.size())
{
cout << *(id_pool.begin()) << endl;
}
else
cout << -1 << endl;
}
else if (orders[0] == 'R')
{
int id_num;
cin >> id_num;
id_pool.erase(id_num);
p_queue.erase(id_num);
}
else if(orders[0] == 'C')
{
cout << p_queue.size() << endl;
}
else if (orders[0] == 'S')
{
for (map<int, int>::iterator p = p_queue.begin(); p != p_queue.end(); ++p)
{
cout << p->first << ' ' << p->second << endl;
}
for (set<int, compare>::iterator q = id_pool.begin(); q != id_pool.end(); ++q)
{
cout << *q << endl;
}
}
}
return 0;
}
2.poj 3714(最近点对问题)
做法是使用分治法,详见https://blog.csdn.net/liufeng_king/article/details/8484284。
注意在调用sqrt()的时候,如果原先里面不是浮点数,那么最好将其转换成浮点数形式,可以写作(double)(...)。
#include "stdafx.h"
#include<cstdio>
#include<algorithm>
#include<cmath>
#define NODE_NUM 100005
#define DIST_MAX 1000000000
using namespace std;
int case_num, N;
typedef long long LL;
struct Node
{
LL x, y;
int id;
Node(LL c_x = 0, LL c_y = 0, int i_id = 0) :x(c_x), y(c_y), id(i_id) {}
const bool operator <(const Node &a)const//学习这里的比较函数的写法
{
return (x == a.x) ? (y < a.y) : (x < a.x);
}
}nodes[NODE_NUM*2];
double dist(int a, int b)//自定义求距离的函数
{
LL x = nodes[a].x - nodes[b].x, y = nodes[a].y - nodes[b].y;
return sqrt(double(x*x+y*y));
}
double DivAndCon(int left, int right)//核心函数:递归求解最短距离
{
if (left == right)//如果是同一个节点,那么返回一个极大值
return DIST_MAX;
int mids = (left + right) >> 1;//求出“中线”
double left_min = DivAndCon(left,mids);//对左右两侧分别递归,求最短距离
double right_min = DivAndCon(mids + 1, right);
double min_d = min(left_min,right_min);
for (int i = mids; i >= left; --i)
{
if (nodes[mids].x - nodes[i].x > min_d)//这里和下面的那个if很重要,用来控制需要暴力求距离的节点数目(理论上不超过6个)
break;
for (int j = mids + 1; j <= right; ++j)
{
if (nodes[j].x - nodes[mids + 1].x > min_d)
break;
double tmp_dist = dist(i, j);
if (nodes[i].id != nodes[j].id && tmp_dist < min_d)
min_d = tmp_dist;//这里我们通过设定id,将其作比较来判断是否是最短距离
}
}
return min_d;
}
int main()
{
while (scanf_s("%d", &case_num) != EOF)
{
for (int t = 0; t < case_num; ++t)
{
scanf_s("%d", &N);
for (int i = 0; i < N; ++i)
{
scanf_s("%lld%lld", &(nodes[i].x), &(nodes[i].y));
nodes[i].id = 0;
}
for (int i = 0; i < N; ++i)
{
scanf_s("%lld%lld", &(nodes[i + N].x), &(nodes[i + N].y));
nodes[i + N].id = 1;
}
sort(nodes, nodes + 2 * N);
double res = DivAndCon(0, 2 * N - 1);
printf("%.3lf\n", res);
}
}
return 0;
}
3.poj 2051 堆排序的简单应用
堆属于stl库,主要有make_heap(),push_heap()和pop_heap()三类。
它们的参数主要有三个:第一,第二个分别是元素的首尾地址(尾地址需要+1),第三个则是比较函数,用来定义大顶堆或者小顶堆。pop_heap()的实际功能是将首元素扔到了最末尾,如果想要删除元素,需要pop_back()操作。
大顶堆需要的是 > 的比较函数,小顶堆则是<.
通常的比较函数(用于sort的)写法是:
const int cmp(const type &A,const type &B)const
{//......
}
如果是专用于模版的,一般需要重载运算符 < ,写法是:
struct cmp
{
bool operator < (const type &a,const type &b)const
{//...
}
};
还有一种是在类的定义的时候就重载运算符,比如:
struct Node
{
int fir,sec;
bool operator < (const Node &a)
{
return (fir == a.fir)?(sec < a.sec):(fir < a.fir);
}
};
下面是本题的代码:
#include<cstdio>
#include<algorithm>
#define Q_NUM 3005
using namespace std;
struct Node
{
int q_num, weight,ori_wei;//这里巧妙地使用了两个权重,一个用来存放原始权重,这很重要!
}nodes[Q_NUM];
bool cmp(const Node& a, const Node& b)
{
return (a.weight == b.weight) ? (a.q_num>b.q_num) : (a.weight>b.weight);
}
char strs[10];
int q_nums,counter;
int main()
{
counter = 0;
while (scanf_s("%s", strs,10) != EOF, strs[0] != '#')
{
scanf_s("%d%d",&(nodes[counter].q_num),&(nodes[counter].ori_wei));
nodes[counter].weight = nodes[counter].ori_wei;
counter++;
push_heap(nodes,nodes+counter,cmp);
}
scanf_s("%d", &q_nums);
for (int i = 0; i < q_nums; ++i)
{
printf("%d\n",nodes[0].q_num);
nodes[0].weight += nodes[0].ori_wei;
pop_heap(nodes, nodes + counter,cmp);
push_heap(nodes,nodes+counter,cmp);
}
return 0;
}
4.poj 1442(treap tree:一种动态平衡二叉树)
我采用了一种简单的方式来实现,开一个最大堆一个最小堆,最大堆用来存放从1到当前get对应的index的数,最小堆则存放从index+1到get[index]序号的数。先将元素插入最小堆中,待插入完成之后,我们将最小堆的首元素与最大堆的首元素进行比较,需要保证最大堆的首元素小于最小堆的首元素,从而使得最大堆中总存放了前index个最小的元素,我们每次get输出的结果就是最大堆的首元素了。
采用priority_queue<LL,vector<LL>,greater<LL> >来实现最小堆。需要注意的是,最小堆的比较函数是greater哦。
#include "stdafx.h"
#include<cstdio>
#include<queue>
#include<vector>
#include<functional>
#define N_NUM 30005
typedef long long LL;
using namespace std;
int get_time,temp_input,M,N;
int querys[N_NUM],datas[N_NUM];
int main()
{
while (scanf_s("%d%d", &M, &N) != EOF)
{
priority_queue<LL,vector<LL>,greater<LL> >fir;//to store the newly input data(小顶堆)
priority_queue<LL,vector<LL>, less<LL> >sec;//to store the already sorted data,all of them must less than fir(大顶堆)
for (int i = 0; i < M; ++i)
{
scanf_s("%d",datas+i);
}
for (int i = 0; i < N; ++i)
{
scanf_s("%d",querys+i);
}
int num_data = 0;
sec.push(datas[num_data++]);
for (int i = 0; i < N; ++i)
{
while(num_data < querys[i])//to insert numbers into fir,then sec
{
fir.push(datas[num_data++]);
while (sec.top() > fir.top())//ensure sec.top() <= fir.top()
{
LL temp_fir = fir.top(),
temp_sec = sec.top();
fir.pop(), sec.pop();
fir.push(temp_sec);
sec.push(temp_fir);
}
}
//to output datas
while (sec.size() < i+1)
{
LL temp_top = fir.top();
fir.pop();
sec.push(temp_top);
}
printf("%lld\n",sec.top());
}
}
return 0;
}
5.poj 2796(所谓的单调栈,不过我觉得应该用双指针法也能实现)
原始思路是:找到所有的局部最小值及其对应的区间(可以想象一下,其时所有的所谓的最大乘积,无非是某段最小值乘以该段长度得到的)。如果对于每个节点,都直接向两边搜索区间的边界,复杂度为O(n^2),这是不可取的。我们可以采用栈的方法来简化复杂度。(我认为,用动态规划,或者双指针法遍历,应该也能取得类似的效果)。
实际写代码的时候,我碰到了一个很难处理的问题,就是求从第i项到第j项的和,由于需要求许多次,而每次都重新计算(j-i)次加法显然不合适,所以我们采用了这样的技术,将前k项的和都存储起来,这样需要第i-j项的和时,只需要计算sums[j]-sums[i]就行了。
第二个tricky的点在于,需要建立一个当前栈顶元素对应的原数组输入的序号。这是在实际过程中写代码的时候发现的需求,所以很不好改。
第三,单调栈是可以通过数组来实现的!多开一个计数器就行了。而且相比之下,这种方式的逻辑更容易理解。
代码如下:
#include "stdafx.h"
#include<cstdio>
#include<vector>
#include<stack>
#include<algorithm>
#define N_MAX 100005
typedef long long LL;
using namespace std;
int N,sta_point,end_point;
int ori_data[N_MAX],lef_side[N_MAX],index[N_MAX];
LL sums[N_MAX];
int main()
{
while (scanf_s("%d", &N) != EOF)
{
memset(sums, 0, sizeof(sums));
LL res = -1;
sta_point = end_point = 0;
stack<int>values;
for (int i = 1; i <= N; ++i)
{
scanf_s("%d",ori_data+i);
sums[i] = sums[i - 1] + ori_data[i];
}
ori_data[++N] = -1;
for (int i = 1; i <= N; ++i)
{
if (values.size() == 0 || ori_data[i] > ori_data[index[values.size()-1]])
{
index[values.size()] = i;
lef_side[i] = i;
values.push(ori_data[i]);
continue;
}
if (ori_data[i] == ori_data[index[values.size() - 1]])
continue;
while (values.size() && ori_data[i] < ori_data[index[values.size() - 1]])
{
values.pop();
LL temp_res = ori_data[index[values.size()]] * (sums[i-1]-sums[lef_side[index[values.size()]]-1]);
if (temp_res > res)
{
sta_point = lef_side[index[values.size()]];
end_point = i - 1;
res = temp_res;
}
}
lef_side[i] = lef_side[index[values.size()]];
index[values.size()] = i;
values.push(ori_data[i]);
}
printf("%lld\n%d %d\n",res,sta_point,end_point);
}
return 0;
}
6.2259 team队列
这题学习点是,为每一个team开一个记录数据的队列,这种偏暴力的方式平时很少见。
代码如下:
#include "stdafx.h"
#include<cstdio>
#include<queue>
using namespace std;
queue<int>teams[1005];//teams[0] depicts index queue,1-N depicts the i-th team's queue
int datas[1000005];//to record the team index of each data element
bool exists[1005];//whether the team is in the index queue or not
int team_num,q_data,case_num;
char operas[8];//the operation string
void clear_func(int T)
{
memset(exists,false,sizeof(exists));
for (int i = 0; i <= T; ++i)
{
while (teams[i].size())
teams[i].pop();
}
}
void record_func(int T)
{
for (int i = 1,temp_len; i <= T; ++i)//team index starts from 1 to T
{
scanf_s("%d",&temp_len);
for (int j = 0,temp_data; j < temp_len; ++j)
{
scanf_s("%d",&temp_data);
datas[temp_data] = i;
}
}
}
void opera_func()
{
while (scanf_s("%s", operas, 8) != EOF && operas[0] != 'S')
{
if (operas[0] == 'E')//enqueue
{
scanf_s("%d",&q_data);
if (exists[datas[q_data]] == false)//not exists in the index queue
{
exists[datas[q_data]] = true;
teams[0].push(datas[q_data]);
teams[datas[q_data]].push(q_data);
}
else
{
teams[datas[q_data]].push(q_data);
}
}
else//dequeue
{
int index_front = teams[0].front();
int to_output = teams[index_front].front();
teams[index_front].pop();
if (teams[index_front].size() == 0)
{
teams[0].pop();
exists[index_front] = false;
}
printf("%d\n",to_output);
}
}
}
int main()
{
case_num = 1;
while (scanf_s("%d", &team_num) != EOF)
{
if (team_num == 0)
break;
clear_func(team_num);
printf("Scenario #%d\n", case_num++);
record_func(team_num);
opera_func();
printf("\n");
}
return 0;
}
7.poj 1577(二叉树)
这里我采用了一个巧妙的方法:用数组来存树的节点,用数组的序号来代替指针表示各个节点,那么原先的left,right的初始值就从NULL变成了-1。利用二叉搜索树的特性,就能构建出一棵树了,然后直接递归输出这课树的前序遍历。
#include "stdafx.h"
#include<iostream>
#include<stack>
#include<string>
using namespace std;
struct TreeNode
{
char val;
int left,right;
}nodes[30];
stack<string>datas;
int counter;
void traverse(int root)
{
if (root < 0)
return ;
cout << nodes[root].val;
traverse(nodes[root].left);
traverse(nodes[root].right);
}
int main()
{
//cin.tie(0);
//ios_base::sync_with_stdio(false);
string strs;
counter = 0;
while (cin>>strs)
{
if (strs[0] != '*' && strs[0] != '$')
datas.push(strs);
else//reconstruct the tree
{
while (datas.size())
{
string temp_top = datas.top();
datas.pop();
for (int i = 0; i < temp_top.size(); ++i)
{
nodes[counter].val = temp_top[i];
nodes[counter].left = nodes[counter].right = -1;//like NULL
counter++;
}
}
for (int i = 1; i < counter; ++i)
{
int root = 0;
while (root >= 0)
{
if (nodes[root].val < nodes[i].val)
{
if (nodes[root].right >= 0)
{
root = nodes[root].right;
}
else
{
nodes[root].right = i;
break;
}
}
else
{
if (nodes[root].left >= 0)
{
root = nodes[root].left;
}
else
{
nodes[root].left = i;
break;
}
}
}
}
//traverse the tree
traverse(0);
cout << endl;
if (strs[0] == '$')
break;
}
counter = 0;
}
return 0;
}
8.poj 1105(二叉树)
首先要强调一点,就是以后少使用常用的表示序列的单词作为变量名,像left,right,rank,index,data之类的,很有可能已经在某个库中被设置成某种特殊的功能的名字了,实在要用,可以在后面加上个_;另外,以后写类的时候,最好将首字母大写。
#include "stdafx.h"
#include<iostream>
#include<string>
using namespace std;
bool datas[128];
int ranks[8];
int depth,times,case_num;
string varis;
int main()
{
cin.tie(0);
ios_base::sync_with_stdio(false);
case_num = 1;
while (cin >> depth)
{
if (!depth)
break;
memset(datas, false, sizeof(datas));
memset(ranks, 0, sizeof(ranks));
for (int i = 0; i < depth; ++i)
{
cin >> varis;
ranks[i] = varis[1] - '0' - 1;
}
cin >> varis;
int len = varis.size();
cout << "S-Tree #" << case_num++ << ":" << endl;
for (int i = 0; i < len; ++i)
{
datas[i] = varis[i] - '0';
}
cin >> times;
for (int i = 0; i < times; ++i)
{
cin >> varis;
int res = 0;
for (int i = 0; i < depth; ++i)
{
res *= 2;
res += varis[ranks[i]]-'0';
}
cout << datas[res];
}
cout << endl<<endl;
}
return 0;
}
9. poj 3349(hash的一种应用)
这题要学习的点有:
(1)memset,memcpy是cstring里的函数。
(2)用邻接链表来存储hash表,思路跟图中用邻接链表存储边是一模一样的。就是存储一个head数组,一个next数组。head数组就是找链表表头的位置的,而next数组则是记录链表的链接关系的。
(3)在hash func的设置上,这里采用了Hash(x) = (sums(x)+multi(x))%p。取一个大质数就行了。至于怎么选择质数,我也不是很清楚。。。比如这道题,我采用999983就不行,采用99991就行了。而且质数的选择对运行时间的影响很大。。。
(4)关于循环体结构中,循环变量的命名,我觉得一般用i,j,k之类的不是不行,只是有时候往往忘了它们的真正意义所在,弄得每层循环的目的都不清楚了,这样反而得不偿失。所以我觉得,可以在循环体边上添加简单的注释,或者给循环变量命名时添加一些简单的注释,比如在读入数据的时候,我们以ri或者r_i命名。
#include "stdafx.h"
#include<cstdio>
#include<cstring>
#define MAX_V 100005
#define PRIMES 99991
using namespace std;
int snows[MAX_V][6],head_hash[MAX_V],next_hash[MAX_V],to_input[6];
int N,hash_num,signal;
int Hash2Int(int *a)//transfer int[6] to int:f(a) = (sum+mul)%P
{
long long res = 0,muls = 1;
for (int i = 0; i < 6; ++i)
{
res = (a[i]+res)%PRIMES;
muls = (a[i]*muls)%PRIMES;
}
return (res + muls) % PRIMES;
}
bool IsEqual(int *a, int *b)//第一次写的时候少了一重循环!!!
{
bool temp_c,temp_a;
for (int i = 0; i < 6; ++i)
{
temp_c = true, temp_a = true;
for (int j = 0; j < 6; ++j)//clockwise
{
if (a[j] != b[(i + j) % 6])
{
temp_c = false;
break;
}
}
if (temp_c)
return true;
for (int j = 0; j < 6; ++j)//anticlockwise
{
if (a[j] != b[(i - j + 6) % 6])
{
temp_a = false;
break;
}
}
if (temp_a)
return true;
}
return false;
}
bool insert_data(int *a)
{
int hash_v = Hash2Int(a);
for (int i = head_hash[hash_v]; i; i = next_hash[i])
{
if (IsEqual(a, snows[i]))
return true;
}
hash_num++;//not exist yet
memcpy(snows[hash_num],a,6*sizeof(int));
next_hash[hash_num] = head_hash[hash_v];
head_hash[hash_v] = hash_num;
return 0;
}
int main()
{
scanf_s("%d", &N);
memset(head_hash,0,sizeof(head_hash));
hash_num = 0;
signal = 1;
for (int i = 0; i < N; ++i)
{
for(int j = 0;j < 6;++j)
scanf_s("%d",to_input+j);
if (insert_data(to_input))
{
printf("Twin snowflakes found.\n");
signal = 0;
break;
}
}
if(signal)
printf("No two snowflakes are alike.\n");
return 0;
}
10.poj 2406(KMP)
这里要提的一点是,如何巧妙利用kmp算法计算出的next数组,来判断字符串重复了多次。
另外,原来有一种叫做Boyer-Moore算法,效果好于KMP算法。
这道题还可以用hash等做法去解,当然我暂时写不出这种代码。。。
下面的代码中kmp()只是我写着练手的,起不到什么作用。
#include "stdafx.h"
#include<cstdio>
#include<iostream>
#include<cstring>
#define N_NUM 1000005
using namespace std;
int Next[N_NUM],res,len;
char T[N_NUM];
char P[N_NUM];
void GetNext()//length of Pattern string
{
len = strlen(P);
Next[0] = -1;
int i = 0, j = -1;//i代表遍历字符串的下标,j代表当前的前缀与后缀集合的交集中最长元素的长度,也即最长偏移量,-1表示向右偏移
while (i < len)
{
if (j == -1 || P[i] == P[j])
{
i++;
j++;
Next[i] = j;
}
else
j = Next[j];
}
}
int KMP(int p_len, int t_len)
{
int i = 0, j = 0;
while (i < t_len && j < p_len)
{
if (j == -1 || T[i] == P[j])
{
i++;
j++;
}
else
j = Next[j];
}
if (j == p_len)
return i - j;
return -1;
}
int main()
{
while (scanf_s("%s", P, N_NUM) != EOF && P[0] != '.')
{
res = 0;
memset(Next,0,sizeof(Next));
GetNext();
if (len % (len - Next[len]) == 0)
printf("%d\n", len / (len - Next[len]));
else
printf("%d\n", 1);
}
return 0;
}
11.poj 1958(四柱汉诺塔)
多想一步,其实这题就是线性动态规划。
#include "stdafx.h"
#include<cstdio>
#include<iostream>
#include<algorithm>
#define INT_MAX 2147483647
using namespace std;
typedef long long LL;
LL dp3[13],dp4[13];
int main()
{
memset(dp3, 0, sizeof(dp3));
memset(dp4, 0, sizeof(dp4));
for (int i = 1; i <= 12; ++i)
{
dp3[i] = (1+dp3[i - 1]) * 2 - 1;
}
for (int i = 1; i <= 12; ++i)
{
LL temp_min = INT_MAX;
for (int k = 0; k < i; ++k)
{
temp_min = min(temp_min,dp4[k]*2+dp3[i-k]);
}
dp4[i] = temp_min;
printf("%lld\n", dp4[i]);
}
return 0;
}
12.poj 1580(暴力匹配字符串与gcd)
这道题的唯二难点大概是写循环的时候要注意,以及默写gcd了吧。
#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
string fir, sec,thi;
int res,signal,nomi,deno;
int ComLen()
{
res = 0;
for (int fir_sta = fir.size() - 1; fir_sta >= 0; --fir_sta)
{
for (int sec_sta = 0; sec_sta < sec.size(); ++sec_sta)
{
int fir_i = fir_sta, sec_i = sec_sta,temp_res = 0;
while (fir_i < fir.size() && sec_i < sec.size())
{
temp_res += (fir[fir_i++] == sec[sec_i++]);
}
res = max(res, temp_res);
}
}
return res;
}
int gcd(int a, int b)
{
if (b == 0)
return a;
return gcd(b, a%b);
}
int main()
{
while (cin >> fir)
{
signal = 0;
if (fir == "-1")
break;
cin >> sec;
deno = fir.size() + sec.size();
if (fir.size() > sec.size())
{
signal = 1;
thi = sec;
sec = fir;
fir = thi;
}
ComLen();
nomi = 2 * res;
int temp = gcd(nomi, deno);
if (temp)
{
nomi /= temp;
deno /= temp;
}
if (signal)
cout << "appx(" << sec << "," << fir << ") = ";
else
cout << "appx(" << fir << "," << sec << ") = ";
if (nomi == 0)
cout << 0 << endl;
else if (nomi == deno)
cout << 1 << endl;
else
cout << nomi << "/" << deno << endl;
}
return 0;
}
13.hdu 2527(huffman encoding)
霍夫曼编码的重要结论:编码该字符串所需的总长度,等于建立的huffman tree的所有非叶子节点的权值。
然后:当你认为你的算法一定没有问题的时候,如果总是不能AC,就想一想特例!
#include "stdafx.h"
#include<iostream>
#include<functional>
#include<string>
#include<queue>
using namespace std;
int case_num, counter[26],len,res,fir_n,m;
string strs;
int main()
{
scanf_s("%d",&case_num);
for (int i = 0; i < case_num; ++i)
{
res = 0;
memset(counter, 0, sizeof(counter));
scanf_s("%d",&m);
cin >> strs;
len = strs.size();
for (int i = 0; i < len; ++i)
{
counter[strs[i] - 'a']++;
}
priority_queue<int,vector<int>,greater<int> >trees;
for (int i = 0; i < 26; ++i)
{
if (counter[i])
trees.push(counter[i]);
}
while (trees.size() > 1)
{
fir_n = trees.top();
trees.pop();
fir_n += trees.top();
trees.pop();
trees.push(fir_n);
res += fir_n;
}
res = max(res, trees.top());//注意考虑特例哟!
if (res <= m)
cout << "yes\n";
else
cout << "no\n";
}
return 0;
}
14.hdu 2193(AVL树之节点与高度的关系)
一个推论:(根节点高度不算)一颗高为h的树,至少由n(h)个节点构成,则节点个数满足递推公式:n(h) = n(h-1)+n(h-2)+1
这个数组其实就是斐波那契数列的一部分(左右两边都加上1就可以发现规律了)。
另外,对斐波那契数列的各项值的估算可以用(5^0.5+1)/2的n次方来进行。
#include "stdafx.h"
#include<cstdio>
using namespace std;
int N;
int fibs[46];
int main()
{
fibs[0] = 1,fibs[1] = 2;
for (int i = 2; i < 46; ++i)
fibs[i] = fibs[i - 1] + fibs[i - 2];
while (scanf_s("%d", &N) != EOF && N)
{
for (int i = 0; i < 46; ++i)
{
if (fibs[i]-1> N)
{
printf("%d\n",i-2);
break;
}
}
}
return 0;
}
15.poj 3481(练习各类平衡树的题目,很经典)
这里提到一个问题,map,set内存储的元素是完全有序的吗?
答案是对的。另外,删除元素,使用erase().
#include "stdafx.h"
#include<cstdio>
#include<map>
using namespace std;
map<int, int>datas;
int orders,K,P;
int main()
{
while (scanf_s("%d", &orders) != EOF && orders)
{
if (orders == 1)//insert data
{
scanf_s("%d%d",&K,&P);
datas.insert(make_pair(P,K));
}
else if (orders == 3)//print min data
{
if (datas.size() == 0)
{
printf("%d\n",0);
continue;
}
map<int, int>::iterator iter = datas.begin();
printf("%d\n",iter->second);
datas.erase(iter);
}
else//print max data
{
if (datas.size() == 0)
{
printf("%d\n", 0);
continue;
}
map<int, int>::iterator iter = datas.end();
iter--;
printf("%d\n", iter->second);
datas.erase(iter);
}
}
return 0;
}