刷oj碰到的问题2(180913-180916)

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;
}

猜你喜欢

转载自blog.csdn.net/georgeandgeorge/article/details/82219107