某农业大学数据结构A-第10周作业

1.哈夫曼编码

【问题描述】读入n个字符所对应的权值,自底向上构造一棵哈夫曼树,自顶向下生成每一个字符对应的哈夫曼编码,并依次输出。另,求解某字符串的哈夫曼编码,求解某01序列的译码。

【输入形式】输入的第一行包含一个正整数n,表示共有n个字符需要编码。其中n不超过100。第二行中有n个用空格隔开的正整数,分别表示n个字符的权值,依次按照abcd...的默认顺序给出。然后是某字符串和某01序列。

【输出形式】前n行,每行一个字符串,表示对应字符的哈夫曼编码。然后是某字符串的哈夫曼编码,某01序列的译码。

【注意】保证每次左子树比右子树的权值小;如出现相同权值的,则先出现的在左子树,即下标小的在左子树。

【样例输入】

8
5 29 7 8 14 23 3 11

aabchg

00011110111111001

【样例输出】

0001
10
1110
1111
110
01
0000
001

000100011011100010000

acdef

#include <bits/stdc++.h>
using namespace std;
typedef char** HuffmanCode;
typedef struct
{
	int weight;
	int parent;
	int LChild;
	int RChild;
}HTNode, HuffmanTree[10001];

void select(HuffmanTree ht, int n, int &s1, int &s2)
{
	int min, _min;//min是最小值,_min是第二小的值,分别赋给左,右子树
	for (int i = 1; i <= n ;i++)
	{
		if (ht[i].parent == 0) {
			min = i; break;
		}
	}
	for (int i = min+1; i <= n; i++)
	{
		if (ht[i].weight < ht[min].weight && ht[i].parent == 0) {
			min = i;
		}
	}
	s1 = min;
	for (int i = 1; i <= n; i++)
	{
		if (ht[i].parent == 0 && i != s1) {
			_min = i;
			break;
		}
	}
	for (int i = _min + 1; i <= n; i++)
	{
		if (ht[i].weight < ht[_min].weight && i != s1 && ht[i].parent == 0) {
			_min = i;
		}
	}
	s2 = _min;
}
void CreHuffmanTree(HuffmanTree &ht, int w[], int n)
{
	for (int i = 1; i <= n; i++) ht[i] = { w[i],0,0,0 };
	int m = 2 * n - 1;
	for (int i = n + 1; i <= m; i++) ht[i] = { 0,0,0,0 };
	for (int i = n + 1; i <= m ; i++)
	{
		int s1, s2;
		select(ht, i - 1, s1, s2);
		ht[i].weight = ht[s1].weight + ht[s2].weight;
		ht[s1].parent = ht[s2].parent = i;
		ht[i].LChild = s1, ht[i].RChild = s2;
	}
}
void CreHuffmanCode(HuffmanTree &ht, HuffmanCode &hc, int n)
{
	hc = (char**)malloc(sizeof(char*) * n + 1);
	char* code = (char*)malloc(sizeof(char) * n);
	code[n - 1] = '\0';
	for (int i = 1; i <= n; i++)
	{
		int start = n - 1;
		int c = i;
		int p = ht[i].parent;
		while (p)
		{
			if (ht[p].LChild == c) code[--start] = '0';
			else code[--start] = '1';
			c = p;
			p = ht[c].parent;
		}
		hc[i] = (char*)malloc((n - start) * sizeof(char));
		strcpy(hc[i], &code[start]);
	}
	free(code);
}
void code(HuffmanTree ht, int n, string s)
{
	int i = 0;
	while (i<(signed)s.size())
	{
		int cur = 2 * n - 1;
		while (ht[cur].LChild != 0 && ht[cur].RChild != 0)
		{
			if (s[i] == '0') {
				cur = ht[cur].LChild;
			}
			else if (s[i] == '1') {
				cur = ht[cur].RChild;
			}
			i++;
		}
		char ch = 'a' + cur - 1;
		cout << ch;
	}
}

int main()
{
	int n, w[10001];
	cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> w[i];
	}
	HuffmanTree ht;
	CreHuffmanTree(ht, w, n);
	HuffmanCode hc;
	CreHuffmanCode(ht, hc, n);
	for (int i = 1; i <= n; i++)
	{
		cout << hc[i] << endl;
	}
	string sample;
	cin >> sample;
	for (int i = 0; i < sample.size(); i++)
	{
		int temp = sample[i] - 96;
		cout << hc[temp];
	}
	cout << endl;
	string s;
	cin >> s;
	code(ht, n, s);
}
 
2.带权路径长度

【问题描述】 输入一串正整数,正整数之间用空格键分开,请建立一棵哈夫曼树,以输入的数字作为叶子节点,求这棵哈夫曼树的带权路径长度。

【输入形式】 首先输入正整数的个数n,然后是对应的n个正整数,正整数个数不超过10个

【输出形式】 输出创建的哈夫曼树的带权路径总长度

【样例输入】 

5

4 5 6 7 8

【样例输出】 

69

 #include<iostream>
using namespace std;

typedef struct node
{
	int weight;
	int l,r,parent;
 }huff;
 
 void select(huff a[],int n,int &q1,int &q2)
 {
 	for(int i=0;i<n;i++)
 	{
 		if(a[i].parent==0)
 		{
 			q1=i;break;
		}
	}
	for(int i=0;i<n;i++)
	{
		if(a[i].parent==0 && a[i].weight<a[q1].weight)
		q1=i;
	}
	
	for(int i=0;i<n;i++)
	{
		if(a[i].parent==0 && i!=q1)
		{
			q2=i;break;
		}
	}
	for(int i=0;i<n;i++)
	{
		if(a[i].weight<a[q2].weight && a[i].parent==0 &&i!=q1)
		{
			q2=i;
		}
	}
} 
 
void creat(int n,huff a[])
 {
    for(int i=0;i<n;i++)
 	{
 		cin >> a[i].weight;
 		a[i].parent=a[i].l=a[i].r=0;
	}
	for(int i=0;i<=(2*n-1);i++)
	{
		a[i].parent=a[i].l=a[i].r=0;
	}
 	int q1,q2;
 	for(int i=n;i<(2*n-1);i++)
 	{
 		select(a,i,q1,q2);
 		a[q1].parent=i;
 		a[q2].parent=i;
 		a[i].l=q1;
 		a[i].r=q2;
 		a[i].weight=a[q1].weight+a[q2].weight;
	 }
 }
 
int gethuff(huff a[],int n)
 {
 	int num,sum=0;
 	for(int i=0;i<n;i++)
 	{
 		num=0;
 		int s=i;
 		while(a[s].parent!=0)
 		{
 			s=a[s].parent;
 			num++;
		 }
		sum += num*a[i].weight;
	}
	return sum;
 }
 
 int main()
 {
 	int n;
 	cin >> n;
 	huff a[100];
	creat(n,a);
	cout << gethuff(a,n);
	return 0;
 }
3.图的遍历及连通性

【问题描述】
 根据输入的图的邻接矩阵A,判断此图的连通分量的个数。请使用邻接矩阵的存储结构创建图的存储,并采用BFS优先遍历算法实现,否则不得分。
【输入形式】
 第一行为图的结点个数n,之后的n行为邻接矩阵的内容,每行n个数表示。其中A[i][j]=1表示两个结点邻接,而A[i][j]=0表示两个结点无邻接关系。
【输出形式】
 输出此图连通分量的个数。
【样例输入】
 5
 0 1 1 0 0
 1 0 1 0 0
 1 1 0 0 0
 0 0 0 0 1
 0 0 0 1 0
【样例输出】
 2
【样例说明】
 邻接矩阵中对角线上的元素都用0表示。(单个独立结点,即与其它结点都没有边连接,也算一个连通分量)

#include<iostream>
#include<queue>
using namespace std;

typedef struct graph
{
	int vertexs;
	int arcs[100][100];
}graph;

int visited[100]={0};//遍历的邻接点,被访问为1,未被访问为0 
void creat(graph &g)
{
	int i,j;
	cin >> g.vertexs;//总数
	for(i=0;i<g.vertexs;i++)
	{
		for(j=0;j<g.vertexs;j++)
		{
			cin >> g.arcs[i][j];
		}
	} 
}

void bfs(graph g,int v)
{
	visited[v]=1;
	queue<int> q;
	q.push(v);
	while(!q.empty())
	{
		v=q.front();
		q.pop();
		for(int i=0;i<g.vertexs;i++)//遍历列j 
		{
			if(g.arcs[v][i]!=0 && visited[i]!=1)
			bfs(g,i);
		}
	}
}

int main()
{
	graph g;
	int i,sum=0;
	creat(g);
	for(i=0;i<g.vertexs;i++)
	{
		if(visited[i]!=1)
		{
			bfs(g,i);//遍历行i 
			sum++;
		}
	}
	cout << sum <<endl;
	return 0;
}
4.犯罪团伙

【题目描述】

此题必须采用邻接表的存储结构,建立图的存储,然后采用DFS遍历实现求解。否则不给分。

警察抓到了 n 个罪犯,警察根据经验知道他们属于不同的犯罪团伙,却不能判断有多少个团伙,但通过警察的审讯,知道其中的一些罪犯之间相互认识,已知同一犯罪团伙的成员之间直接或间接认识。有可能一个犯罪团伙只有一个人。请你根据已知罪犯之间的关系,确定犯罪团伙的数量。已知罪犯的编号从 1 至 n。

【输入】

第一行:n(<=1000,罪犯数量),第二行:m(<5000,关系数量)以下若干行:每行两个数:I 和 j,中间一个空格隔开,表示罪犯 i 和罪犯 j 相互认识。

【输出】

一个整数,犯罪团伙的数量。

【样例输入】

11

8

1 2

4 3

5 4

1 3

5 6

7 10

5 10

8 9

【输出】

3



#include<iostream>
using namespace std;

int visited[100]={0};//判断是否被访问,是1,否0 
typedef struct arcnode//边表
{
	int adjvex;
	struct arcnode*nextarc;
 }arcnode;
 
 typedef struct vertexnode//顶点表
 {
 	int data;
 	arcnode*firstarc;
  } vertexnode;
  
  typedef struct //邻接表
  {
  	vertexnode vertex[100];
  	int vexnum,arcnum;
   } adjlist;
   
void creat(adjlist &g)
{
	cin >> g.vexnum >>g.arcnum;
	int x,y,i;
	for(i=0;i<g.vexnum;i++)
	{
		g.vertex[i].firstarc=NULL;
	}
	for(i=0;i<g.arcnum;i++)
	{
		cin >> x >>y;
		arcnode*p1;
		p1=new arcnode;
		p1->adjvex=y;
		p1->nextarc=g.vertex[x].firstarc;
		g.vertex[x].firstarc=p1;
		
		arcnode*p2;
		p2=new arcnode;
		p2->adjvex=x;
		p2->nextarc=g.vertex[y].firstarc;
		g.vertex[y].firstarc=p2;
	}
}   

void DFS(adjlist &g,int v)
{
	int j;
	visited[v]=1;
	arcnode*p=g.vertex[v].firstarc;
	while(p)
	{
		j=p->adjvex;
		if(visited[j]==0)
		{
			DFS(g,j);
		}
		p=p->nextarc;
	}
}

int main()
{
	adjlist g;
	creat(g);
	int i,sum=0;
	for(i=0;i<g.vexnum;i++)
	{
		if(visited[i]!=1)
		{
			DFS(g,i);
			sum++;
		}
	}
	cout << sum <<endl;
	return 0;
}


5.图形窗口问题

【问题描述】

在某图形操作系统中,有N个窗口,每个窗口都是一个两边与坐标轴分别平行的矩形区域。窗口的边界上的点也属于该窗口。窗口之间有层次的区别,在多于一个窗口重叠的区域里,只会显示位于顶层的窗口里的内容。

当你点击屏幕上一个点的时候,你就选择了处于被点击位置的最顶层窗口,并且这个窗口就会被移到所有窗口的最顶层,而剩余的窗口的层次顺序不变。如果你点击的位置不属于任何窗口,则系统会忽略你这次点击。

现在我们希望你写一个程序模拟点击窗口的过程。

【输入形式】

输入的第一行有两个正整数,即N和M。(1<=N<=10,1<=M<=10)接下来N行按照从最下层到最顶层的顺序给出N个窗口的位置。每行包含四个非负整数x1,y1,x2,y2,表示该窗口的一对顶点坐标分别为(x1,y1)和(x2,y2)。保证x1<x2,y1<y2。

接下来M行每行包含两个非负整数x,y,表示一次鼠标点击的坐标。题目中涉及到的所有点和矩形的顶点的x,y坐标分别不超过2559和1439。

【输出形式】

输出包括M行,每一行表示一次鼠标点击的结果。如果该次鼠标点击选择了一个窗口,则输出这个窗口的编号(窗口按照输入中的顺序从1编号到N);如果没有,则输出"IGNORED"(不含双引号)。

【样例输入】

3 4

0 0 4 4

1 1 5 5

2 2 6 6 

1 1

0 0

4 4

0 5

【样例输出】

2

1

1

IGNORED

【样例说明】

第一次点击的位置同时属于第1和第2个窗口,但是由于第2个窗口在上面,它被选择并且被置于顶层。

第二次点击的位置只属于第1个窗口,因此该次点击选择了此窗口并将其置于顶层。现在的三个窗口的层次关系与初始状态恰好相反了。第三次点击的位置同时属于三个窗口的范围,但是由于现在第1个窗口处于顶层,它被选择。

最后点击的(0,5)不属于任何窗口。

#include<iostream>
using namespace std;

struct window//储存一个窗口的坐标 
{
	int wx1,wx2;
	int wy1,wy2;
	int num;
 } ;
 
 struct click//储存一次鼠标点击的结果
 {
 	int x,y;
  };
  
  int main()
  {
  	int M,N;
  	cin >> M >> N;
  	window w[M+N];
  	click c[N];
  	int temp=0;
  	//cout << M <<N;
  	
  	for(int i=0;i<M;i++)
  	{
  		cin >> w[i].wx1 >>w[i].wy1>>w[i].wx2>>w[i].wy2;
		w[i].num = i+1;
	}
	
	for(int i=0;i<N;i++)
	{
		cin >> c[i].x>>c[i].y;
		int flag=0,j;
		for(j=M+temp-1;j>=0;j--)
		{
			if(c[i].x<=w[j].wx2&&c[i].x>=w[j].wx1&&
			c[i].y<=w[j].wy2&&c[i].y>=w[j].wy1)
			{
				cout << w[j].num <<endl;
				flag=1;
				temp++;
				w[M+temp-1]=w[j];//被点击窗口置于顶层 
				break;
			} 
		}
		if(flag==0)
		cout << "IGNORED"<<endl;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值