PTA 堆,哈夫曼树,哈夫曼编码

:用于处理优先级(表现为某个值的最大或最小值)问题
特性:
1.用数组表示的完全二叉树(这样就可以用数组脚标i来整活了)
2.任一根节点都比左右儿子要大/小(但左儿子并不一定大于/小于右儿子,根据插入顺序来决定)

以下是题目:
树7 堆中的路径 (25分)
将一系列给定数字插入一个初始为空的小顶堆H[]。随后对任意给定的下标i,打印从H[i]到根结点的路径。
输入格式:
每组测试第1行包含2个正整数N和M(≤1000),分别是插入元素的个数、以及需要打印的路径条数。下一行给出区间[-10000, 10000]内的N个要被插入一个初始为空的小顶堆的整数。最后一行给出M个下标。
输出格式:
对输入中给出的每个下标i,在一行中输出从H[i]到根结点的路径上的数据。数字间以1个空格分隔,行末不得有多余空格。
输入样例:
5 3
46 23 26 24 10
5 4 3
输出样例:
24 23 10
46 23 10
26 10

思路:题目要求建立一个最小堆并打印路径。先建一个空数组,然后一个个读进来数字,进行插入。在插入过程中,如果插入元素小于父节点值则交换值。最后按要求打印即可。

#include <iostream>
#include <stdio.h>
#include <stdlib.h>

using namespace std;

const int MaxNum = 10000;
const int MinNum = -10000;

int H[MaxNum], Hsize;
void Create()
{
	Hsize = 0;
	H[0] = MinNum;
}
void Insert(int X)
{
	int i;
	for (i = ++Hsize; H[i/2]> X; i /= 2)
	{
		H[i] = H[i / 2];   //若父节点大于儿子,则交换值
	}
	H[i] = X;		//若跳出循环,则当前位置i就是合适位置
}
void OutPut(int j)
{
	for (; j > 0; j /= 2)
	{
		if (j != 1)
			cout << H[j] << " ";
		else
			cout << H[j];
	}
}

int main()
{	
	int N,M;
	cin >> N >>M;
	if (0==N) return 0;

	Create();
	for (int i = 0; i < N; i++)//创建并写入
	{
		int X;
		cin >>  X;
		Insert(X);
	}

	for (int i = 0; i < M; i++)//按规则打印
	{
		int j;
		cin >> j;
		OutPut(j);
		if (i != M - 1) cout << "\n";

	}
	return 0;
}

集合运算: 用一个根节点下面挂N个儿子来表示集合,判断是否同集合则返回判断节点的根来做比较。

05-树8 File Transfer (25分)
We have a network of computers and a list of bi-directional connections. Each of these connections allows a file transfer from one computer to another. Is it possible to send a file from any computer on the network to any other?
Input Specification:
Each input file contains one test case. For each test case, the first line contains N (2≤N≤10​4​​ ), the total number of computers in a network. Each computer in the network is then represented by a positive integer between 1 and N. Then in the following lines, the input is given in the format:
I c1 c2
where I stands for inputting a connection between c1 and c2; or
C c1 c2
where C stands for checking if it is possible to transfer files between c1 and c2; or
S
where S stands for stopping this case.
Output Specification:
For each C case, print in one line the word “yes” or “no” if it is possible or impossible to transfer files between c1 and c2, respectively. At the end of each case, print in one line “The network is connected.” if there is a path between any pair of computers; or “There are k components.” where k is the number of connected components in this network.

Sample Input 1:
5
C 3 2
I 3 2
C 1 5
I 4 5
I 2 4
C 3 5
S
Sample Output 1:
no
no
yes
There are 2 components.

Sample Input 2:
5
C 3 2
I 3 2
C 1 5
I 4 5
I 2 4
C 3 5
I 1 3
C 1 5
S
Sample Output 2:
no
no
yes
yes
The network is connected.

**题意及思路:**题目大概意思就是给你12345…这样连续的N个自然数,一开始大家都是互相独立的。然后C代表check,如C 1 5代表检查1 5 是否是连接的。I 代表 将两个元素链接。然后最后判断一下一共有几个集合。考虑用集合来做,其中要注意的是find中要规避不必要的循环,union中要注意条件判断将小规模的树挂在大规模的树下方,避免树的高度增长过快。(用数组中的负数的负几来表示底下带了几个儿子,方便做规模判断)

#include <iostream>
#include <stdio.h>
#include <stdlib.h>

using namespace std;

const int MaxNum = 10e4;

struct SetType {
	int Data;
	int Parent;
};

SetType S[MaxNum];

int Find(SetType S[],int X,int N) 
{
	int i = X-1;
	//for (; i < N && S[i].Data != X; i++);//遍历找i
	if (i > N)  //没到到返回-1
		return -1;
	for (; S[i].Parent >= 0; i = S[i].Parent);
	//找到根节点脚标
	return i;
}

void Union(SetType S[],int Root1,int Root2) 
{
	//用-3表示根节点带了2个儿子,以此类推
	if (S[Root1].Parent > S[Root2].Parent)
	{
		S[Root2].Parent += S[Root1].Parent;//将Root1Root2的节点和相加
		S[Root1].Parent = Root2;//将Root1挂在Root2底下
	}
	else
	{
		S[Root1].Parent += S[Root2].Parent;
		S[Root2].Parent = Root1;
	}

}

int CaculateComponents(SetType S[],int N)
{
	int Components = 0;   //因为儿子必然指向父节点
	for (int i = 0; i < N; i++)  //所以有几个负数代表有几个根
		if (S[i].Parent < 0) Components++;
			
	return Components;
}

int main() 
{
	char Todo;
	int N;
	int x1, x2;
	//初始化数组
	cin >> N;
	for (int i = 0; i < N; i++)
	{
		S[i].Data = i+1;
		S[i].Parent = -1;
	}

	cin >> Todo;
	while (Todo != 'S')
	{
		cin >> x1 >> x2;

		int Root1, Root2;//无论做union还是find都要找根
		Root1 = Find(S, x1, N);
		Root2 = Find(S, x2, N);//提前计算避免重复

		if (Todo == 'C') //check
		{
			if (Root1 == Root2 &&
				Root1>= 0  && Root2>= 0 )
				cout << "yes" << "\n";
			else
				cout << "no" << "\n";
		}
		else if (Todo == 'I') //combine
			Union(S,Root1,Root2);

		cin >> Todo;
	}

	int K;
	K = CaculateComponents(S, N);
	if (K > 1)
		cout << "There are " << K << " components.";
	else
		cout << "The network is connected.";
	
	return 0;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值