数据结构二

记录TITOCHAN学习数据结构的历程

DS图—图的邻接矩阵存储及度计算

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 72 Solved: 25

Description

假设图用邻接矩阵存储。输入图的顶点信息和边信息,完成邻接矩阵的设置,并计算各顶点的入度、出度和度,并输出图中的孤立点(度为0的顶点)

–程序要求–

若使用C++只能include一个头文件iostream;若使用C语言只能include一个头文件stdio

程序中若include多过一个头文件,不看代码,作0分处理

不允许使用第三方对象或函数实现本题的要求

Input

测试次数T,每组测试数据格式如下:

图类型 顶点数 (D—有向图,U—无向图)

顶点信息

边数

每行一条边(顶点1 顶点2)或弧(弧尾 弧头)信息

Output

每组测试数据输出如下信息(具体输出格式见样例):

图的邻接矩阵

按顶点信息输出各顶点的度(无向图)或各顶点的出度 入度 度(有向图)。孤立点的度信息不输出。

图的孤立点,每行一个。若没有孤立点,不输出任何信息。

Sample

Input

Copy

2
D 5
V1 V2 V3 V4 V5
7
V1 V2
V1 V4
V2 V3
V3 V1
V3 V5
V4 V3
V4 V5
U 5
A B C D E
5
A B
A C
B D
D C
A D
Output

Copy

0 1 0 1 0
0 0 1 0 0
1 0 0 0 1
0 0 1 0 1
0 0 0 0 0
V1: 2 1 3
V2: 1 1 2
V3: 2 2 4
V4: 2 1 3
V5: 0 2 2
0 1 1 1 0
1 0 0 1 0
1 0 0 1 0
1 1 1 0 0
0 0 0 0 0
A: 3
B: 2
C: 2
D: 3
E
#include <iostream>
using namespace std;

int strchu(string s)
{
	int count = 0;
	for (int i = 0; i < s.length(); i++)
	{

		count += s[i];
	}
	return count;
}
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		char c;
		int point;
		cin >> c >> point;
		int **a = new int *[point + 1];
		for (int i = 0; i <= point; i++)
		{
			a[i] = new int[point + 1];
		}
		string chr = " ";
		for (int i = 0; i <= point; i++)
		{
			for (int j = 0; j <= point; j++)
			{
				a[i][j] = 0;
			}
		}
		for (int i = 1; i <= point; i++)
		{
			string c1;
			cin >> c1;
			chr += (c1 + " ");
			int count = strchu(c1);
			a[0][i] = count;
			a[i][0] = count;
		}
		int n;
		cin >> n;

		if (c == 'D')
		{
			for (int i = 0; i < n; i++)
			{
				string c1, c2;
				cin >> c1 >> c2;
				int count1 = strchu(c1);
				int count2 = strchu(c2);
				int x, y;
				for (int j = 1; j <= point; j++)
				{
					if (a[j][0] == count1)
					{
						x = j;
					}
					if (a[0][j] == count2)
					{
						y = j;
					}
				}
				a[x][y] = 1;
			}
			for (int i = 1; i <= point; i++)
			{
				for (int j = 1; j <= point; j++)
				{
					cout << a[i][j] << " ";
				}
				cout << endl;
			}
			int cs = 0;
			for (int i = 1; i <= point; i++)
			{
				int count = 0, inc = 0, outc = 0;
				while (chr[++cs] != ' ')
				{
					cout << chr[cs];
				}
				for (int j = 1; j <= point; j++)
				{
					if (a[i][j] == 1)
					{
						inc++;
					}
				}
				for (int j = 1; j <= point; j++)
				{
					if (a[j][i] == 1)
					{
						outc++;
					}
				}
				count = inc + outc;
				if (count == 0)
				{
					cout << endl;
				}
				else
				{
					cout << ": " << inc << " " << outc << " " << count << endl;
				}
			}
		}
		else
		{
			for (int i = 0; i < n; i++)
			{
				string c1, c2;
				cin >> c1 >> c2;
				int count1 = strchu(c1);
				int count2 = strchu(c2);
				int x, y;
				for (int j = 1; j <= point; j++)
				{
					if (a[j][0] == count1)
					{
						x = j;
					}
					if (a[0][j] == count2)
					{
						y = j;
					}
				}
				a[x][y] = 1;
				a[y][x] = 1;
			}
			for (int i = 1; i <= point; i++)
			{
				for (int j = 1; j <= point; j++)
				{
					cout << a[i][j] << " ";
				}
				cout << endl;
			}
			int cs = 0;
			for (int i = 1; i <= point; i++)
			{
				int count = 0;
				while (chr[++cs] != ' ')
				{
					cout << chr[cs];
				}
				for (int j = 1; j <= point; j++)
				{
					if (a[i][j] == 1)
					{
						count++;
					}
				}
				for (int j = 1; j <= point; j++)
				{
					if (a[j][i] == 1)
					{
						count++;
					}
				}
				if (count == 0)
				{
					cout << endl;
				}
				else
				{
					cout << ": " << count / 2 << endl;
				}
			}
		}
	}
	return 0;
}

DS图遍历–深度优先搜索

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 11 Solved: 8

Description

给出一个图的邻接矩阵,对图进行深度优先搜索,从顶点0开始

注意:图n个顶点编号从0到n-1

如果图不连通,则对尚未访问的编号结点继续进行深度优先搜索,直到所有结点被访问

Input

第一行输入t,表示有t个测试实例

第二行输入n,表示第1个图有n个结点

第三行起,每行输入邻接矩阵的一行,以此类推输入n行

第i个结点与其他结点如果相连则为1,无连接则为0,数据之间用空格隔开

以此类推输入下一个示例

Output

每行输出一个图的深度优先搜索结果,结点编号之间用空格隔开

Sample

Input

Copy

2
4
0 0 1 1
0 0 1 1
1 1 0 1
1 1 1 0
5
0 0 0 1 1
0 0 1 0 0
0 1 0 1 1
1 0 1 0 0
1 0 1 0 0
Output

Copy

0 2 1 3 
0 3 2 1 4 
#include <iostream>
#include <vector>
using namespace std;

void DFS(vector<vector<int>> &tu, vector<int> &zhaoguo, int node)
{
	cout << node << " ";
	zhaoguo[node] = 1;
	for (int i = 0; i < tu[node].size(); i++)
	{
		if (tu[node][i] == 1 && zhaoguo[i] == 0)
		{
			DFS(tu, zhaoguo, i);
		}
	}
}

void solve(vector<vector<int>> &tu)
{
	int n = tu.size();
	vector<int> zhaoguo(n, 0);
	for (int i = 0; i < n; i++)
	{
		if (zhaoguo[i] == 0)
		{
			DFS(tu, zhaoguo, i);
			
		}
	}
}

int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		int n;
		cin >> n;
		vector<vector<int>> tu(n, vector<int>(n));
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < n; j++)
			{
				cin >> tu[i][j];
			}
		}
		solve(tu);
		cout << endl;
	}
	return 0;
}

DS图遍历–广度优先搜索

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 3 Solved: 3

Description

给出一个图的邻接矩阵,对图进行广度优先搜索,从顶点0开始

注意:图n个顶点编号从0到n-1

如果图不连通,则对尚未访问的编号结点继续进行广度优先搜索,直到所有结点被访问

Input

第一行输入t,表示有t个测试实例

第二行输入n,表示第1个图有n个结点

第三行起,每行输入邻接矩阵的一行,以此类推输入n行

第i个结点与其他结点如果相连则为1,无连接则为0,数据之间用空格隔开

以此类推输入下一个示例

Output

每行输出一个图的广度优先搜索结果,结点编号之间用空格隔开

Sample

Input

Copy

2
4
0 0 1 1
0 0 1 1
1 1 0 1
1 1 1 0
5
0 0 0 1 1
0 0 1 0 0
0 1 0 1 1
1 0 1 0 0
1 0 1 0 0
Output

Copy

0 2 3 1 
0 3 4 2 1 
#include <iostream>
#include <queue>
#include <vector>
using namespace std;

void BFS(vector<vector<int>> &tu, vector<int> &zhaoguo, int node)
{
	queue<int> q;
	q.push(node);
	zhaoguo[node] = 1;
	while (!q.empty())
	{
		int curr = q.front();
		q.pop();
		cout << curr << " ";
		for (int i = 0; i < tu[curr].size(); i++)
		{
			if (tu[curr][i] == 1 && zhaoguo[i] == 0)
			{
				q.push(i);
				zhaoguo[i] = 1;
			}
		}
	}
}

void solve(vector<vector<int>> &tu)
{
	int n = tu.size();
	vector<int> zhaoguo(n, 0);
	for (int i = 0; i < n; i++)
	{
		if (zhaoguo[i] == 0)
		{
			BFS(tu, zhaoguo, i);
		}
	}
}

int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		int n;
		cin >> n;
		vector<vector<int>> tu(n, vector<int>(n));
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < n; j++)
			{
				cin >> tu[i][j];
			}
		}
		solve(tu);
		cout << endl;
	}
	return 0;
}

图的应用之——图的连通

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 10 Solved: 4

Description

给定一个图的邻接矩阵,请判断该图是否是连通图。连通图:任意两个顶点之间都有路径。

–程序要求–

若使用C++只能include一个头文件iostream;若使用C语言只能include一个头文件stdio

程序中若include多过一个头文件,不看代码,作0分处理

不允许使用第三方对象或函数实现本题的要求

Input

第1行输入一个整数k,表示有k个测试数据

第2行输入一个整数n,表示有n个结点

从第3行起到第n+2行输入一个邻接矩阵,其中Matrix[i,j]=1表示第i,j个结点之间有边,否则不存在边。

接下来是第2到第k个测试数据的结点数和邻接矩阵

Output

输出Yes or No表示图是否是强连通图

Sample

Input

Copy

2
4
0 1 1 1 
1 0 1 1 
1 1 0 1 
1 1 1 0 
7
0 1 0 0 0 0 0 
0 0 1 1 0 0 0 
1 0 0 0 0 0 0 
1 0 1 0 0 0 0 
0 0 0 0 0 1 1 
0 1 0 0 0 0 0 
0 0 0 1 0 1 0 
Output

Copy

Yes
No
#include <iostream>
#include <vector>
using namespace std;

void DFS(vector<vector<int>> &tu, vector<int> &zhaoguo, int node, int n)
{
	zhaoguo[node] = 1;
	for (int i = 0; i < n; i++)
	{
		if (tu[node][i] == 1 && zhaoguo[i] == 0)
		{
			DFS(tu, zhaoguo, i, n);
		}
	}
}

int iscon(vector<vector<int>> &tu, int n)
{
	vector<int> zhaoguo(n,0);
	for (int i = 0; i < n; i++)
	{
		fill(zhaoguo.begin(), zhaoguo.end(), 0);
		if (zhaoguo[i] == 0)
		{
			DFS(tu, zhaoguo, i, n);
			for (int j = 0; j < n; j++)
			{
				if (!zhaoguo[j])
				{
					return 0;
				}
			}
		}
	}
	return 1;
}

int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		int n;
		cin >> n;
		vector<vector<int>> tu(n, vector<int>(n));
		for (int i = 0; i < n; i++)
		{
			for (int j = 0; j < n; j++)
			{
				cin >> tu[i][j];
			}
		}
		int re = iscon(tu,n);
		if (re)
		{
			cout << "Yes";
		}
		else
		{
			cout << "No";
		}
		cout << endl;
	}
	return 0;
}

图综合练习–构建邻接表

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 3 Solved: 3

Description

已知一有向图,构建该图对应的邻接表。

邻接表包含数组和单链表两种数据结构,其中每个数组元素也是单链表的头结点,数组元素包含两个属性,属性一是顶点编号info,属性二是指针域next指向与它相连的顶点信息。

单链表的每个结点也包含两个属性,属性一是顶点在数组的位置下标,属性二是指针域next指向下一个结点。

Input

第1行输入整数t,表示有t个图

第2行输入n和k,表示该图有n个顶点和k条弧。

第3行输入n个顶点。

第4行起输入k条弧的起点和终点,连续输入k行

以此类推输入下一个图

Output

输出每个图的邻接表,每行输出格式:数组下标 顶点编号-连接顶点下标-……-^,数组下标从0开始。

具体格式请参考样例数据,每行最后加入“^”表示NULL。

Sample

Input

Copy

1
5 7
A B C D E
A B
A D
A E
B D
C B
C E
E D
Output

Copy

0 A-1-3-4-^
1 B-3-^
2 C-1-4-^
3 D-^
4 E-3-^
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;

struct Node
{
	char info;
	Node *next;
};

int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		int n, k;
		cin >> n >> k;
		vector<Node *> linjie(n);
		unordered_map<char, int> zidian;
		for (int i = 0; i < n; i++)
		{
			char c;
			cin >> c;
			linjie[i] = new Node{c, nullptr};
			zidian[c] = i;
		}
		for (int i = 0; i < k; i++)
		{
			char u, v;
			cin >> u >> v;
			Node *newnode = new Node{v, nullptr};
			Node *cur = linjie[zidian[u]];
			while (cur->next)
			{
				cur = cur->next;
			}
			cur->next = newnode;
		}
		for (int i = 0; i < n; i++)
		{
			cout << i << " " << linjie[i]->info;
			Node *cur = linjie[i]->next;
			while (cur)
			{
				cout << "-" << zidian[cur->info];
				cur = cur->next;
			}
			cout << "-^\n";
		}
	}
	return 0;
}

DS图—图的连通分量

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 55 Solved: 32

Description

输入无向图顶点信息和边信息,创建图的邻接矩阵存储结构,计算图的连通分量个数。

Input

测试次数t

每组测试数据格式如下:

第一行:顶点数 顶点信息

第二行:边数

第三行开始,每行一条边信息

Output

每组测试数据输出,顶点信息和邻接矩阵信息

输出图的连通分量个数,具体输出格式见样例。

每组输出直接用空行分隔。

Sample

Input

Copy

3
4 A B C D
2
A B
A C
6 V1 V2 V3 V4 V5 V6
5
V1 V2
V1 V3
V2 V4
V5 V6
V3 V5
8 1 2 3 4 5 6 7 8
5
1 2
1 3
5 6
5 7
4 8

Output

Copy

A B C D
0 1 1 0
1 0 0 0
1 0 0 0
0 0 0 0
2

V1 V2 V3 V4 V5 V6
0 1 1 0 0 0
1 0 0 1 0 0
1 0 0 0 1 0
0 1 0 0 0 0
0 0 1 0 0 1
0 0 0 0 1 0
1

1 2 3 4 5 6 7 8
0 1 1 0 0 0 0 0
1 0 0 0 0 0 0 0
1 0 0 0 0 0 0 0
0 0 0 0 0 0 0 1
0 0 0 0 0 1 1 0
0 0 0 0 1 0 0 0
0 0 0 0 1 0 0 0
0 0 0 1 0 0 0 0
3
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;

void dfs(int v, vector<vector<int>>& ad, vector<bool>& visited) {
    visited[v] = 1;
    for (int i = 0; i < ad.size(); i++) {
        if (ad[v][i] && !visited[i]) {
            dfs(i, ad, visited);
        }
    }
}

int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		string str="";
		int point,b;
		cin >> point;
		vector<vector<int>> ad(point, vector<int>(point, 0));
		unordered_map<string, int> index;
		for(int i=0;i<point;i++)
		{
			string s;
			cin >> s;
			if(i==0)
			{
				str += s;
			}
			else
			{
				str += " " + s;
			}
			index[s] = i;
		}
		cin>>b;
		for(int i=0;i<b;i++)
		{
			string s1,s2;
			cin >> s1 >> s2;
			ad[index[s1]][index[s2]] = 1;
			ad[index[s2]][index[s1]] = 1;
		}
		int count=0;
		vector<bool> visited(point, 0);
		for(int i=0;i<point;i++)
		{
			if(!visited[i])
			{
				dfs(i,ad,visited);
				count++;
			}
		}
		cout<<str<<endl;
		for(int i=0;i<point;i++)
		{
			for(int j=0;j<point;j++)
			{
				cout<<ad[i][j]<<" ";
			}
			cout<<endl;
		}
		cout<<count<<endl<<endl;
	}
	return 0;
}

DS图—最小生成树

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 54 Solved: 21

Description

根据输入创建无向网。分别用Prim算法和Kruskal算法构建最小生成树。(假设:输入数据的最小生成树唯一。)

Input

顶点数n

n个顶点

边数m

m条边信息,格式为:顶点1 顶点2 权值

Prim算法的起点v

Output

输出最小生成树的权值之和

对两种算法,按树的生长顺序,输出边信息(Kruskal中边顶点按数组序号升序输出)

Sample

Input

Copy

6
v1 v2 v3 v4 v5 v6 
10
v1 v2 6
v1 v3 1
v1 v4 5
v2 v3 5
v2 v5 3
v3 v4 5
v3 v5 6
v3 v6 4
v4 v6 2
v5 v6 6
v1
Output

Copy

15
prim:
v1 v3 1
v3 v6 4
v6 v4 2
v3 v2 5
v2 v5 3
kruskal:
v1 v3 1
v4 v6 2
v2 v5 3
v3 v6 4
v2 v3 5
#include <iostream>
using namespace std;
struct
{
	string ad;
	int lc;
} cedge[100];
class tu
{
public:
	int graph[100][100], graph1[100][100];
	int n, len;
	int visited[100],low[100];
	string *q;
	string start;
	int startpos;
	tu(){};
	void Settu()
	{
		int i, j;
		cin >> n;
		for (i = 0; i < 100; i++)
			for (j = 0; j < 100; j++)
			{
				graph[i][j] = 10000;
				graph1[i][j] = 10000;
			}

		q = new string[n];
		for (i = 0; i < n; i++)
			cin >> q[i];
		cin >> len;
		for (i = 1; i <= len; i++)
		{
			string ch1, ch2;
			int weight;
			cin >> ch1 >> ch2 >> weight;
			int loc1, loc2;
			for (j = 0; j < n; j++)
			{
				if (q[j] == ch1)
					loc1 = j;
				if (q[j] == ch2)
					loc2 = j;
			}
			graph1[loc1][loc2] = graph[loc1][loc2] = weight;
			graph1[loc1][loc2] = graph[loc2][loc1] = weight;
		}
		cin >> start;
		for (i = 0; i < n; i++)
			if (q[i] == start)
				startpos = i;
	}
	void prim()
	{
		int i, j;
		for (i = 1; i <= n; i++)
			visited[i] = 0;
		visited[startpos] = 1;
		int min;
		for (i = 0; i < n; i++)
		{
			min = 99999;
			for (j = 0; j < n; j++)
			{
				if (graph[i][j] < min)
				{
					min = graph[i][j];
					cedge[i].ad = q[j];
					cedge[i].lc = min;
				}
			}
		}
		string s3;
		string *e1, *e2;
		int *w3;
		e1 = new string[100];
		e2 = new string[100];
		w3 = new int[100];
		int index, k = 0;
		for (i = 0; i < n; i++)
		{
			min = 99999;
			for (j = 0; j < n; j++)
			{
				if (!visited[j])
					continue;
				else
				{
					if (min > cedge[j].lc)
					{
						min = cedge[j].lc;
						s3 = cedge[j].ad;
						index = j;
					}
				}
			}
			e1[k] = q[index];
			e2[k] = s3, w3[k++] = min;
			for (int g = 0; g < n; g++)
			{
				if (q[g] == s3)
				{
					visited[g] = 1;
					break;
				}
			}
			for (int g = 0; g < n; g++)
			{
				min = 99999;
				for (int m = 0; m < n; m++)
				{
					if (min > graph[g][m] && visited[m] == 0)
					{
						min = graph[g][m];
						cedge[g].ad = q[m];
						cedge[g].lc = min;
					}
				}
			}
		}
		int weight = 0;
		for (i = 0; i < k - 1; i++)
		{
			weight += w3[i];
		}
		cout << weight << endl;
		cout << "prim:" << endl;
		for (i = 0; i < k - 1; i++)
			cout << e1[i] << " " << e2[i] << " " << w3[i] << endl;
	}
	void kruskal()
	{
		cout << "kruskal:" << endl;
		int *uni = new int[n];
		for (int i = 0; i < n; i++)
		{
			uni[i] = i;
		}
		for (int i = 0; i < n - 1; i++)
		{
			int min = 99999;
			int x, y;
			for (int j = 0; j < n; j++)
			{
				for (int l = 0; l < n; l++)
				{
					if (j == l)
						continue;
					if (uni[j] == uni[l])
						continue;
					else
					{
						if (min > graph1[j][l])
						{
							min = graph1[j][l];
							x = j;
							y = l;
						}
					}
				}
			}
			graph1[x][y] = 10000;
			graph1[y][x] = 10000;
			if (x > y)
			{
				int k;
				k = x;
				x = y;
				y = k;
			}

			for (int i = 0; i < n; i++)
			{
				if (uni[i] == uni[y] && i != y)
					uni[i] = uni[x];
			}
			uni[y] = uni[x];
			cout << q[x] << " " << q[y] << " " << min << endl;
		}
	}
	void show()
	{
		int i, j;
		for (i = 0; i < n; i++)
		{
			for (j = 0; j < n; j++)
				cout << graph[i][j] << " ";
			cout << endl;
		}
	}
};
int main()
{
	tu m, M;
	m.Settu();
	m.prim();
	m.kruskal();
}

DS图_冗余连接

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 23 Solved: 17

Description

树可以看作是一个连通且无环的无向图。

给定往一颗n个结点(结点值1~n)的树中添加一条边后的图。添加的边的两个顶点包含在1到n中间,且这条附加的边不属于树中已存在的边。

图的信息记录于长度为n的二维数组edges,edges[i] = [a, b]表示图中在a和b之间存在一条边。

请找出一条可以删去的边,删除后可以使得剩余部分是一个有着n个结点的树。如果有多个可以删去的边,则输出数组edges中最后出现的那条边。

Input

第一行输入t,表示有t个测试样例。

接着,输入n,接着输入长度为n的edges数组。

以此类推,共输入t个测试样例。

Output

每一行输出当前测试样例的结果。

共输出t行。

Sample

Input

Copy

3

3
1 2
1 3
2 3

5
1 2
2 3
3 4
1 4
1 5

8
1 8
4 8
1 2
1 3
4 5
4 6
3 5
5 7
Output

Copy

2 3
1 4
3 5
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
int parent[1005];
int rank1[1005];
int find(int i)
{
	while (parent[i] != -1)
		i = parent[i];
	return i;
}
int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		memset(parent, -1, sizeof(parent));
		memset(rank1, 0, sizeof(rank1));
		int p;
		cin >> p;
		vector<vector<int>> edges;
		for (int i = 0; i < p; i++)
		{
			int a, b;
			cin >> a >> b;
			edges.push_back({a, b});
		}

		int ans[2] = {0};
		for (int i = 0; i < edges.size(); i++)
		{
			int root1 = find(edges[i][0]);
			int root2 = find(edges[i][1]);
			if (root1 == root2)
			{
				ans[0] = edges[i][0];
				ans[1] = edges[i][1];
			}
			else
			{
				if (rank1[root1] > rank1[root2])
					parent[root2] = root1;
				else if (rank1[root1] < rank1[root2])
					parent[root1] = root2;
				else
				{
					parent[root2] = root1;
					rank1[root2]++;
				}
			}
		}
		cout << ans[0] << " " << ans[1]<<"\n";
	}
}

图综合练习–拓扑排序

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 18 Solved: 16

Description

已知有向图,顶点从0开始编号,求它的求拓扑有序序列。

拓扑排序算法:给出有向图邻接矩阵

  1. 逐列扫描矩阵,找出入度为0且编号最小的顶点v
  2. 输出v,并标识v已访问
  3. 把矩阵第v行全清0

重复上述步骤,直到所有顶点输出为止

–程序要求–

若使用C++只能include一个头文件iostream;若使用C语言只能include一个头文件stdio

程序中若include多过一个头文件,不看代码,作0分处理

不允许使用第三方对象或函数实现本题的要求

Input

第一行输入一个整数t,表示有t个有向图

第二行输入n,表示图有n个顶点

第三行起,输入n行整数,表示图对应的邻接矩阵

以此类推输入下一个图的顶点数和邻接矩阵

Output

每行输出一个图的拓扑有序序列

Sample

Input

Copy

2
5
0 1 0 1 1
0 0 1 0 0
0 0 0 0 1
0 0 1 0 0
0 0 0 0 0
7
0 0 0 0 0 0 0
1 0 1 1 0 0 0
1 0 0 0 0 0 0
1 0 1 0 0 0 0
0 0 0 0 0 1 1
0 1 0 0 0 0 0
0 0 0 1 0 1 0
Output

Copy

0 1 3 2 4 
4 6 5 1 3 2 0 
#include <iostream>
#include <queue>
#include <vector>
using namespace std;

vector<int> topoSort(vector<vector<int>> &graph, int n)
{
	vector<int> inDegree(n, 0);
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			inDegree[j] += graph[i][j];

	queue<int> q;
	for (int i = 0; i < n; i++)
		if (inDegree[i] == 0)
			q.push(i);

	vector<int> topoOrder;
	while (!q.empty())
	{
		int v = q.front();
		q.pop();
		topoOrder.push_back(v);
		for (int i = 0; i < n; i++)
		{
			if (graph[v][i])
			{
				inDegree[i]--;
				if (inDegree[i] == 0)
					q.push(i);
			}
		}
	}
	return topoOrder;
}

int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		int n;
		cin >> n;
		vector<vector<int>> graph(n, vector<int>(n));
		for (int i = 0; i < n; i++)
			for (int j = 0; j < n; j++)
				cin >> graph[i][j];

		vector<int> topoOrder = topoSort(graph, n);
		for (int v : topoOrder)
			cout << v << " ";
		cout << "\n";
	}
	return 0;
}

DS图_课程表

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 33 Solved: 15

Description

小明这个学期必须选修n门课程,课程编号记为0到n-1。

在选修某些课程之前需要一些先修课程。先修课程按数组prerequisites给出,其中prerequisites[i] = [a, b],表示如果要学习课程a则必须先学习课程b。

例如,先修课程对[0, 1]表示:要想学习课程0,则需要先完成课程1。

请判断小明能否完成所有课程的学习,如果可以则输出true,否则输出false。

Input

第一行输入t,表示有t个测试样例。

接着输入n,表示有n门课程,接着输入len,表示prerequisites数组的长度,接着输入prerequisites数组。

以此类推,共输入t个测试样例。

Output

每一行输出能否完成所有课程的学习,若可以则输出true,否则输出false。

共输出t行。

Sample

Input

Copy

3

2
1
1 0

2
2
1 0
0 1

3
3
1 0
2 0
2 1
Output

Copy

true
false
true
#include <iostream>
#include <queue>
#include <vector>
using namespace std;

bool canFinish(vector<vector<int>> &prerequisites, int numCourses)
{
	vector<int> inDegree(numCourses, 0);
	for (auto &p : prerequisites)
		inDegree[p[0]]++;

	queue<int> q;
	for (int i = 0; i < numCourses; i++)
		if (inDegree[i] == 0)
			q.push(i);

	while (!q.empty())
	{
		int course = q.front();
		q.pop();
		for (auto &p : prerequisites)
		{
			if (p[1] == course)
			{
				inDegree[p[0]]--;
				if (inDegree[p[0]] == 0)
					q.push(p[0]);
			}
		}
	}

	for (int i = 0; i < numCourses; i++)
		if (inDegree[i] != 0)
			return false;

	return true;
}

int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		int n, len;
		cin >> n >> len;
		vector<vector<int>> prerequisites(len, vector<int>(2));
		for (int i = 0; i < len; i++)
			cin >> prerequisites[i][0] >> prerequisites[i][1];

		bool result = canFinish(prerequisites, n);
		cout << (result ? "true" : "false") << "\n";
	}
	return 0;
}

DS图_传递信息

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 28 Solved: 19

Description

小明在和他的小伙伴们玩传消息游戏,游戏规则如下:

\1. 有n名玩家,所有玩家编号分别为0~n-1,其中小明编号为0;

\2. 每个玩家都有固定的若干个可传信息的其他玩家(也可能没有)。传消息的关系是单向的(即,有向边)。

\3. 每轮信息必须传递给另一个人,且信息可重复经过同一个人。

给定总玩家数n,以及按[玩家编号,对应可传递玩家编号]关系组成的二维数组relation。输出信息从小明(编号0)经过k轮传递到编号为n-1的小伙伴处的方案数;若不能到达,则输出0。

例如,对于n = 5, len = 7, relation = [[0,2],[2,1],[3,4],[2,3],[1,4],[2,0],[0,4]], k = 3,信息从编号0处开始,经3轮传递,到达编号4,共有3种方案:分别是0->2->0->4,0->2->1->4,0->2->3->4。

Input

第一行输入t,表示有t个测试样例。

接着,首先输入n,表示有n名玩家,接着输入len,表示接下来要输入的二维数组的长度,接着依次输入relation数组,接着输入k。

以此类推,共输入t个测试样例。

Output

每一行输出当前测试样例的方案数量。

以此类推共输出t行。

Input

Copy

3

5
7
0 2
2 1
3 4
2 3
1 4
2 0
0 4
3

3
2
0 2
2 1
2

4
6
0 1
0 2
0 3
1 2
1 3
2 3
3
Output

Copy

3
0
1
#include <iostream>
#include <vector>
using namespace std;

int numWays(vector<vector<int>> &relation, int n, int k)
{
	vector<vector<int>> dp(k + 1, vector<int>(n));
	dp[0][0] = 1;
	for (int i = 0; i < k; i++)
		for (auto &r : relation)
			dp[i + 1][r[1]] += dp[i][r[0]];
	return dp[k][n - 1];
}

int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		int n, len, k;
		cin >> n >> len;
		vector<vector<int>> relation(len, vector<int>(2));
		for (int i = 0; i < len; i++)
			cin >> relation[i][0] >> relation[i][1];
		cin >> k;

		int ways = numWays(relation, n, k);
		cout << ways << "\n";
	}
	return 0;
}

DS图应用–最短路径

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 19 Solved: 8

Description

给出一个图的邻接矩阵,再给出指定顶点v0,求顶点v0到其他顶点的最短路径

Input

第一行输入t,表示有t个测试实例

第二行输入n,表示第1个图有n个结点

第三行起,每行输入邻接矩阵的一行,以此类推输入n行

第i个结点与其他结点如果相连则为1,无连接则为0,数据之间用空格隔开

第四行输入v0,表示求v0到其他顶点的最短路径距离

以此类推输入下一个示例

Output

每行输出v0到某个顶点的最短距离和最短路径

每行格式:v0编号-其他顶点编号—-[最短路径],具体请参考示范数据

Sample

Input

Copy

1
5
0 5 0 7 15
0 0 5 0 0
0 0 0 0 1
0 0 2 0 0
0 0 0 0 0
0
Output

Copy

0-1-5----[0 1 ]
0-2-9----[0 3 2 ]
0-3-7----[0 3 ]
0-4-10----[0 3 2 4 ]
#include <iostream>
#include <stack>
using namespace std;

const int maxlen = 20;
const int maxdist = 9999;

int map[maxlen][maxlen];
int point;

void matrix(int vnum, int mx[maxlen][maxlen])
{
	point = vnum;
	for (int i = 0; i < point; i++)
	{
		for (int j = 0; j < point; j++)
		{
			map[i][j] = maxdist;
		}
	}
	for (int i = 0; i < point; i++)
	{
		for (int j = 0; j < point; j++)
		{
			if (mx[i][j])
				map[i][j] = mx[i][j];
		}
	}
}

int findMinDist(int *dist, bool *final)
{
	int min = maxdist, k;
	for (int i = 0; i < point; i++)
	{
		if (!final[i] && dist[i] < min)
		{
			min = dist[i];
			k = i;
		}
	}
	return k;
}

void displayPath(int v0, int *path, int *dist)
{
	for (int i = 0; i < point; i++)
	{
		if (i == v0)
		{
			i++;
			if (i == point)
				return;
		}
		cout << v0 << "-" << i << "-" << dist[i] << "----[" << v0 << " ";
		stack<int> s;
		int j = i;
		while (path[j] != v0)
		{
			s.push(path[j]);
			j = path[j];
		}
		while (!s.empty())
		{
			cout << s.top() << " ";
			s.pop();
		}
		cout << i << " ]\n";
	}
}

void minroad(int v0)
{
	int *dist = new int[point];
	bool *final = new bool[point];
	int *path = new int[point];

	for (int i = 0; i < point; i++)
	{
		dist[i] = map[v0][i];
		final[i] = false;
		path[i] = (dist[i] != maxdist) ? v0 : -1;
	}
	final[v0] = true;
	int num = 1;
	while (num < point)
	{
		int min = findMinDist(dist, final);
		final[min] = true;
		for (int i = 0; i < point; i++)
		{
			if (!final[i] && dist[min] + map[min][i] < dist[i])
			{
				dist[i] = dist[min] + map[min][i];
				path[i] = min;
			}
		}
		num++;
	}
	displayPath(v0, path, dist);
	delete[] path;
	delete[] final;
	delete[] dist;
}

int main()
{
	int t;
	cin >> t;
	for (int k = 0; k < t; k++)
	{
		int vnum, v0;
		int mx[maxlen][maxlen];
	

		for (int i = 0; i < maxlen; i++)
		{
			for (int j = 0; j < maxlen; j++)
			{
				mx[i][j] = 0;
			}
		}
		cin >> vnum;
		for (int i = 0; i < vnum; i++)
		{
			for (int j = 0; j < vnum; j++)
			{
				cin >> mx[i][j];
			}
		}
		matrix(vnum, mx);
		cin >> v0;
		minroad(v0);
	}
	return 0;
}

追星

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 37 Solved: 8

Description

城市总共有N座。yintama是右京女神的狂热粉,当他得知右京女神将要在城市N举办演唱会的时候,马上开始准备动身前往城市N。原本他可以直接乘飞机直达城市N,然而贫穷使他屈服,他必须选择总花费最少的那条路径。

设总共有N座城市(2<=N<=1000),城市编号分别为1,2,3……N。M条航线(1<=M<=2000),每条航线连接两座城市,相互可以到达(无向的)。

yintama目前在身在城市1,求最后yintama参加右京女神演唱会所需要的最少花费。(PS:重边考虑一下?)

Input

有多组输入。

第一行输入一个N、M,代表城市的总数,以及航线的总数。

接下来M行,每行输入三个数字u v w,代表城市u、v之间存在航线,机票花费为w。

Output

每行输出一个数,代表yintama参加右京女神演唱会所需的最少花费。

Sample

Input

Copy

5 5
1 2 20
2 3 30
3 4 20
4 5 20
1 5 100
Output

Copy

90
#include <iostream>
#include <vector>
#include <climits>
using namespace std;

void Dijkstra(vector<vector<int>> &cost, vector<int> &dist)
{
	int N = cost.size();
	vector<bool> s(N, false);
	for (int i = 1; i < N; i++)
		dist[i] = cost[0][i];
	s[0] = true;
	dist[0] = 0;
	for (int i = 1; i < N; i++)
	{
		int minCost = INT_MAX;
		int u = 0;
		for (int j = 1; j < N; j++)
			if (!s[j] && dist[j] < minCost)
			{
				u = j;
				minCost = dist[j];
			}
		s[u] = true;
		for (int j = 1; j < N; j++)
			if (!s[j] && cost[u][j] < INT_MAX && dist[u] + cost[u][j] < dist[j])
				dist[j] = dist[u] + cost[u][j];
	}
}

int main()
{
	int N, M;
	cin >> N >> M;

	vector<vector<int>> cost(N, vector<int>(N, INT_MAX));
	for (int i = 0; i < M; i++)
	{
		int u, v, w;
		cin >> u >> v >> w;
		u--;
		v--;
		cost[u][v] = min(cost[u][v], w);
		cost[v][u] = min(cost[v][u], w);
	}

	vector<int> dist(N, INT_MAX);
	Dijkstra(cost, dist);

	cout << dist[N - 1] << endl;

	return 0;
}

图的顶点可达闭包

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 10 Solved: 6

Description

给定有向图的邻接矩阵A,其元素定义为:若存在顶点i到顶点j的有向边则A[i,j]=1,若没有有向边则A[i,j]= 0。试求A的可达闭包矩阵A*,其元素定义为:若存在顶点i到顶点j的有向路径则A*[i,j]=1,若没有有向路径则A*[i,j]= 0

Input

第1行顶点个数n

第2行开始的n行有向图的邻接矩阵,元素之间由空格分开

Output

有向图的可达闭包矩阵A*,元素之间由空格分开

Sample

Input

Copy

4
0 1 0 1
0 0 1 0
0 0 0 0
0 0 0 0
Output

Copy

0 1 1 1
0 0 1 0
0 0 0 0
0 0 0 0
#include <iostream>
#include <vector>
using namespace std;

void bibao(vector<vector<int>> &reach)
{
	int n = reach.size();
	for (int k = 0; k < n; k++)
		for (int i = 0; i < n; i++)
			for (int j = 0; j < n; j++)
				if (reach[i][k] && reach[k][j])
					reach[i][j] = 1;
}

int main()
{
	int n;
	cin >> n;
	vector<vector<int>> reach(n, vector<int>(n));
	for (int i = 0; i < n; i++)
		for (int j = 0; j < n; j++)
			cin >> reach[i][j];
	bibao(reach);
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < n; j++)
			cout << reach[i][j] << " ";
		cout << endl;
	}
	return 0;
}

货币套汇(图路径)

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 6 Solved: 5

Description

套汇是指利用货币汇兑率的差异将一个单位的某种货币转换为大于一个单位的同种货币。例如,假定1 美元可以买0.7 英镑,1 英镑可以买9.5 法郎,1法郎可以买到0.16美元。通过货币兑换,一个商人可以从1 美元开始买入,得到0.7×9.5×0.16=1.064美元,从而获得6.4%的利润。 给定n种货币c1 ,c2 ,… ,cn的有关兑换率,试设计一个有效算法,确定货币间是否存在套汇的可能性。

提示:判断图上是否出现正环,即环上所有的边相乘大于1

Input

第一行:测试数据组数

每组测试数据格式为:

第一行:正整数n (1< =n< =30),正整数m,分别表示n种货币和m种不同的货币兑换率。

2~n+1行,n种货币的名称。

n+2~n+m+1行,每行有3 个数据项ci,rij 和cj ,表示货币ci 和cj的兑换率为 rij。

Output

对每组测试数据,如果存在套汇的可能则输出YES

如果不存在套汇的可能,则输出NO。

Sample

Input

Copy

2
3 3
USDollar
BritishPound
FrenchFranc
USDollar 0.5 BritishPound
BritishPound 10.0 FrenchFranc
FrenchFranc 0.21 USDollar
3 6
USDollar
BritishPound
FrenchFranc
USDollar 0.5 BritishPound
USDollar 4.9 FrenchFranc
BritishPound 10.0 FrenchFranc
BritishPound 1.99 USDollar
FrenchFranc 0.09 BritishPound
FrenchFranc 0.19 USDollar
Output

Copy

YES
NO
#include <iostream>
#include <vector>
#include <map>
#include <string>
using namespace std;

bool cha(vector<vector<double>> &rate)
{
	int n = rate.size();
	for (int k = 0; k < n; k++)
		for (int i = 0; i < n; i++)
			for (int j = 0; j < n; j++)
				rate[i][j] = max(rate[i][j], rate[i][k] * rate[k][j]);
	for (int i = 0; i < n; i++)
		if (rate[i][i] > 1.0)
			return true;
	return false;
}

int main()
{
	int t;
	cin >> t;
	while (t--)
	{
		int n, m;
		cin >> n >> m;
		map<string, int> tran;
		for (int i = 0; i < n; i++)
		{
			string name;
			cin >> name;
			tran[name] = i;
		}

		vector<vector<double>> rate(n, vector<double>(n, 0));
		for (int i = 0; i < m; i++)
		{
			string ci, cj;
			double rij;
			cin >> ci >> rij >> cj;
			rate[tran[ci]][tran[cj]] = rij;
		}

		if (cha(rate))
			cout << "YES" << endl;
		else
			cout << "NO" << endl;
	}
	return 0;
}

查找

DS静态查找之顺序查找

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 104 Solved: 27

Description

给出一个队列和要查找的数值,找出数值在队列中的位置,队列位置从1开始

要求使用带哨兵的顺序查找算法

Input

第一行输入n,表示队列有n个数据

第二行输入n个数据,都是正整数,用空格隔开

第三行输入t,表示有t个要查找的数值

第四行起,输入t个数值,输入t行

Output

每行输出一个要查找的数值在队列的位置,如果查找不成功,输出字符串error

Sample#0

Input

Copy

8
33 66 22 88 11 27 44 55
3
22
11
99
Output

Copy

3
5
error
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
int main()
{
   int n;
   while (cin >> n)
   {

      vector<int> v(n);
      for (int i = 0; i < n; i++)
         cin >> v[i];

      int t;
      cin >> t;
      while (t--)
      {
         int x, f = 0;
         queue<int> pq;
         for (int i = 0; i < n; i++)
            pq.push(v[i]);
         cin >> x;
         int ans = 0;
         while (!pq.empty())
         {
            ans++;
            if (pq.front() == x)
            {
               cout << ans << endl;
               f = 1;
            }
            pq.pop();
         }
         if (f == 0)
            cout << "error" << endl;
      }
   }

   return 0;
}
/**********************************************************************
	Problem: 1046
	User: 
	Language: C++
	Result: AC
	Time:101 ms
	Memory:2220 kb
**********************************************************************/

DS静态查找之顺序索引查找

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 94 Solved: 21

Description

给出一个队列和要查找的数值,找出数值在队列中的位置,队列位置从1开始

要求使用顺序索引查找算法,其中索引表查找和块内查找都采用不带哨兵、从头开始的顺序查找方法。

Input

第一行输入n,表示主表有n个数据

第二行输入n个数据,都是正整数,用空格隔开

第三行输入k,表示主表划分为k个块,k也是索引表的长度

第四行输入k个数据,表示索引表中每个块的最大值

第五行输入t,表示有t个要查找的数值

第六行起,输入t个数值,输入t行

Output

每行输出一个要查找的数值在队列的位置和查找次数,数据之间用短划线隔开,如果查找不成功,输出字符串error

Sample#0

Input

Copy

18
22 12 13 8 9 20 33 42 44 38 24 48 60 58 74 57 86 53
3
22 48 86
6
13
5
48
40
53
90
Output

Copy

3-4
error
12-8
error
18-9
error
#include <iostream>
#include <queue>
#include <vector>
using namespace std;

struct group
{
  queue<int> q;
  int max;
  int num;
};

int main()
{
  int n;
  while (cin >> n)
  {
    vector<int> v(n);
    for (int i = 0; i < n; i++)
      cin >> v[i];
    int k;
    cin >> k;
    vector<group> g(k);
    int num = 0;
    for (int i = 0; i < k; i++)
    {
      int x;
      cin >> x;
      g[i].max = x;
      g[i].num = num;
      for (int j = num; v[j] <= x; j++)
      {
        g[i].q.push(v[j]);
        num++;
      }
    }

    int t;
    cin >> t;
    while (t--)
    {
      vector<group> gg(k);
      gg = g;
      int x, f = 0;
      cin >> x;
      int ans = 0, sum = 0;
      for (int i = 0; i <= k; i++)
      {
        int ji = 0;
        while (!gg[i].q.empty())
        {
          ji++;
          sum++;
          // cout << g[i].q.front()<<" ";
          if (gg[i].q.front() == x)
          {
            cout << ji + gg[i].num << "-" << i + ji + 1 << endl;
            f = 1;
            break;
          }
          gg[i].q.pop();
        }
        // cout << g[i].num<<endl;
        if (f == 1 || sum == num)
        {
          break;
        }
      }
      if (f == 0)
        cout << "error" << endl;
    }
  }
  return 0;
}

DS查找——折半查找求平方根

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 22 Solved: 21

Description

假定输入y是整数,我们用折半查找来找这个平方根。在从0y之间必定有一个取值是y的平方根,如果我们查找的数xy的平方根小,则x^2<y,如果我们查找的数xy的平方根大,则x^2>y,我们可以据此缩小查找范围,当我们查找的数足够准确时(比如满足|x2-y|<0.00001),就可以认为找到了y的平方根。

比如求5的平方根x,则x一定满足 0<=x<=5,取x(5+0)/2=2.5,因为2.5的平方为6.25>5,所以x一定小于2.5,也即x满足0<=x<=2.5,取x1.25,以此类推

X的范围X的取值x2x2-y
052.56.251.25
02.51.251.5625-3.4375
1.252.51.8753.515625-1.484375
1.8752.52.18754.78515625-0.21484375
2.18752.52.343755.4931640630.493164063
2.18752.343752.2656255.1330566410.133056641
2.18752.2656252.2265625

最后求得5的平方根为2.236

温馨提示: 计算过程中为确保精确性,计算变量的类型都用double

保留小数位数请采用printf("%.3f\n",x) 的格式输出或cout<<fixed<<setprecision(3)<<x<<endl;

程序框架参考平时练习中折半查找的方法

Input

第 1 行输入一个整数n < 100,表示有n个数

从第 2 行起到第n+1行输入n个整数

Output

输出n个数的平方根,精确到小数点后三位。

Sample#0

Input

Copy

2
13
5
Output

Copy

3.606
2.236
#include<iostream>
#include<cmath>
#include<iomanip>
using namespace std;

double Search(double y) {
    double low = 0.0, high = y;
    double mid = (low + high) / 2;
    while(fabs(mid * mid - y) >= 0.00001) {
        if(mid * mid > y) {
            high = mid;
        } else {
            low = mid;
        }
        mid = (low + high) / 2;
    }
    return mid;
}

int main() {
    int n;
    cin >> n;
    while(n--) {
        double y;
        cin >> y;
        double re = Search(y);
        cout << fixed << setprecision(3) << re << endl;
    }
    return 0;
}
/**********************************************************************
	Problem: 1049
	User: 
	Language: C++
	Result: AC
	Time:11 ms
	Memory:2220 kb
**********************************************************************/

DS二叉排序树之查找

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 57 Solved: 21

Description

给出一个数据序列,建立二叉排序树,并实现查找功能

对二叉排序树进行中序遍历,可以得到有序的数据序列

Input

第一行输入t,表示有t个数据序列

第二行输入n,表示首个序列包含n个数据

第三行输入n个数据,都是自然数且互不相同,数据之间用空格隔开

第四行输入m,表示要查找m个数据

从第五行起,输入m行,每行一个要查找的数据,都是自然数

以此类推输入下一个示例

Output

第一行输出有序的数据序列,对二叉排序树进行中序遍历可以得到

从第二行起,输出查找结果,如果查找成功输出查找次数,如果查找失败输出-1

以此类推输出下一个示例的结果

Sample#0

Input

Copy

1
6
22 33 55 66 11 44
7
11
22
33
44
55
66
77
Output

Copy

11 22 33 44 55 66 
2
1
2
4
3
4
-1
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

struct treenode
{
  int val;
  treenode *left;
  treenode *right;
  treenode(int x) : val(x), left(NULL), right(NULL) {}
};

treenode *insert(treenode *root, int val)
{
  if (root == NULL)
  {
    root = new treenode(val);
    return root;
  }
  if (val < root->val)
  {
    root->left = insert(root->left, val);
  }
  else
  {
    root->right = insert(root->right, val);
  }
  return root;
}

void inorder(treenode* root,vector<int> &re)
{
  if(root==NULL)
  {
    return;
  }
  inorder(root->left,re);
  re.push_back(root->val);
  inorder(root->right,re);
}

int find(treenode* root ,int val)
{
  int depth=1;
  while(root!=NULL)
  {
    if(root->val==val)
    {
      return depth;
    }
    else if(root->val>val)
    {
      root=root->left;
    }
    else
    {
      root=root->right;
    }
    depth++;
  }
  return -1;
}

int main()
{
  int t,n,m;
  cin>>t;
  while(t--)
  {
    cin>>n;
    treenode *root=NULL;
    for(int i=0;i<n;i++)
    {
      cin>>m;
      if(i==0)
      {
        root=insert(root,m);
      }
      else
      {
        insert(root,m);
      }
    }
    vector<int> re;
    inorder(root,re);
    for(int i=0;i<re.size();i++)
    {
      cout<<re[i]<<" ";
    }
    cout<<endl;
    cin>>m;
    while(m--)
    {
      cin>>n;
      cout<<find(root,n)<<endl;
    }
  }
  return 0;
}

DS二叉排序树之创建和插入

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 26 Solved: 23

Description

给出一个数据序列,建立二叉排序树,并实现插入功能

对二叉排序树进行中序遍历,可以得到有序的数据序列

Input

第一行输入t,表示有t个数据序列

第二行输入n,表示首个序列包含n个数据

第三行输入n个数据,都是自然数且互不相同,数据之间用空格隔开

第四行输入m,表示要插入m个数据

从第五行起,输入m行,每行一个要插入的数据,都是自然数且和前面的数据不等

以此类推输入下一个示例

Output

第一行输出有序的数据序列,对二叉排序树进行中序遍历可以得到

从第二行起,输出插入第m个数据后的有序序列,输出m行

以此类推输出下一个示例的结果

Sample

0

Input

Copy

1
6
22 33 55 66 11 44
3
77
50
10
Output

Copy

11 22 33 44 55 66 
11 22 33 44 55 66 77 
11 22 33 44 50 55 66 77 
10 11 22 33 44 50 55 66 77 
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

struct treenode
{
  int val;
  treenode *left;
  treenode *right;
  treenode(int x) : val(x), left(NULL), right(NULL) {}
};

treenode *insert(treenode *root, int val)
{
  if (root == NULL)
  {
    root = new treenode(val);
    return root;
  }
  if (val < root->val)
  {
    root->left = insert(root->left, val);
  }
  else
  {
    root->right = insert(root->right, val);
  }
  return root;
}

void inorder(treenode *root, vector<int> &re)
{
  if (root == NULL)
  {
    return;
  }
  inorder(root->left, re);
  re.push_back(root->val);
  inorder(root->right, re);
}

int find(treenode *root, int val)
{
  int depth = 1;
  while (root != NULL)
  {
    if (root->val == val)
    {
      return depth;
    }
    else if (root->val > val)
    {
      root = root->left;
    }
    else
    {
      root = root->right;
    }
    depth++;
  }
  return -1;
}

int main()
{
  int t, n, m;
  cin >> t;
  while (t--)
  {
    cin >> n;
    treenode *root = NULL;
    for (int i = 0; i < n; i++)
    {
      cin >> m;
      if (i == 0)
      {
        root = insert(root, m);
      }
      else
      {
        insert(root, m);
      }
    }
    vector<int> res;
    inorder(root, res);
    for (int i = 0; i < res.size(); i++)
    {
      cout << res[i] << " ";
    }
    cout << endl;
    cin >> n;
    while (n--)
    {
      cin >> m;
      insert(root, m);
      vector<int> re;
      inorder(root, re);
      for (int i = 0; i < re.size(); i++)
      {
        cout << re[i] << " ";
      }
      cout << endl;
    }
  }
  return 0;
}

DS二叉排序树之删除

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 33 Solved: 9

Description

给出一个数据序列,建立二叉排序树,并实现删除功能

对二叉排序树进行中序遍历,可以得到有序的数据序列

Input

第一行输入t,表示有t个数据序列

第二行输入n,表示首个序列包含n个数据

第三行输入n个数据,都是自然数且互不相同,数据之间用空格隔开

第四行输入m,表示要删除m个数据

从第五行起,输入m行,每行一个要删除的数据,都是自然数

以此类推输入下一个示例

Output

第一行输出有序的数据序列,对二叉排序树进行中序遍历可以得到

从第二行起,输出删除第m个数据后的有序序列,输出m行

以此类推输出下一个示例的结果

Sample

#0

Input

Copy

1
6
22 33 55 66 11 44
3
66
22
77
Output

Copy

11 22 33 44 55 66 
11 22 33 44 55 
11 33 44 55 
11 33 44 55
#include <iostream>
#include <vector>
using namespace std;

struct TreeNode
{
  int val;
  TreeNode *left;
  TreeNode *right;
  TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

TreeNode *insert(TreeNode *root, int val)
{
  if (root == NULL)
  {
    return new TreeNode(val);
  }
  if (val < root->val)
  {
    root->left = insert(root->left, val);
  }
  else
  {
    root->right = insert(root->right, val);
  }
  return root;
}

void inorder(TreeNode *root, vector<int> &result)
{
  if (root == NULL)
  {
    return;
  }
  inorder(root->left, result);
  result.push_back(root->val);
  inorder(root->right, result);
}

TreeNode *minValNode(TreeNode *node)
{
  TreeNode *current = node;
  while (current && current->left != nullptr)
  {
    current = current->left;
  }
  return current;
}

TreeNode *deleteNode(TreeNode *root, int val)
{
  if (root == nullptr)
  {
    return root;
  }

  if (val < root->val)
  {
    root->left = deleteNode(root->left, val);
  }
  else if (val > root->val)
  {
    root->right = deleteNode(root->right, val);
  }
  else
  {
    if (root->left == nullptr)
    {
      TreeNode *temp = root->right;
      delete root;
      return temp;
    }
    else if (root->right == nullptr)
    {
      TreeNode *temp = root->left;
      delete root;
      return temp;
    }

    TreeNode *temp = minValNode(root->right);
    root->val = temp->val;
    root->right = deleteNode(root->right, temp->val);
  }
  return root;
}

int main()
{
  int t, n, m;
  cin >> t;
  while (t--)
  {
    cin >> n;
    TreeNode *root = NULL;
    for (int i = 0; i < n; i++)
    {
      cin >> m;
      root = insert(root, m);
    }

    vector<int> res;
    inorder(root, res);
    for (int val : res)
    {
      cout << val << " ";
    }
    cout << endl;

    cin >> n;
    for (int i = 0; i < n; i++)
    {
      cin >> m;
      root = deleteNode(root, m);
      res.clear();
      inorder(root, res);
      for (int val : res)
      {
        cout << val << " ";
      }
      cout << endl;
    }
  }
  return 0;
}

DS查找—二叉树平衡因子

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 3 Solved: 3

Description

二叉树用数组存储,将二叉树的结点数据依次自上而下,自左至右存储到数组中,一般二叉树与完全二叉树对比,比完全二叉树缺少的结点在数组中用0来表示。

计算二叉树每个结点的平衡因子,并按后序遍历的顺序输出结点的平衡因子。

–程序要求–

若使用C++只能include一个头文件iostream;若使用C语言只能include一个头文件stdio.h

程序中若include多过一个头文件,不看代码,作0分处理

不允许使用第三方对象或函数实现本题的要求

Input

测试次数t

每组测试数据一行,数组元素个数n,后跟n个字符,二叉树的数组存储。

Output

对每组测试数据,按后序遍历的顺序输出树中结点的平衡因子(测试数据没有空树)

Sample

#0

Input

Copy

2
6 ABC00D
24 ABCD0EF0000H00000000000I
Output

Copy

B 0
D 0
C 1
A -1
D 0
B 1
I 0
H 1
E 2
F 0
C 2
A -2
#include <iostream>
using namespace std;

int max(int a, int b)
{
  return (a > b) ? a : b;
}

int height(char *tree, int n, int index)
{
  if (index >= n || tree[index] == '0')
    return 0;
  return 1 + max(height(tree, n, 2 * index + 1), height(tree, n, 2 * index + 2));
}

void input(char *tree, int n, int index)
{
  if (index >= n || tree[index] == '0')
    return;
  input(tree, n, 2 * index + 1);
  input(tree, n, 2 * index + 2);
  if (tree[index] != '0')
  {
    int leftHeight = height(tree, n, 2 * index + 1);
    int rightHeight = height(tree, n, 2 * index + 2);
    cout << tree[index] << " " << (leftHeight - rightHeight) << endl;
  }
}

int main()
{
  int t, n;
  cin >> t;
  while (t--)
  {
    cin >> n;
    char *tree = new char[n];
    for (int i = 0; i < n; ++i)
    {
      cin >> tree[i];
    }
    input(tree, n, 0);
    delete[] tree;
  }
  return 0;
}

DS二叉平衡树构建

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 1 Solved: 1

Description

在初始为空的平衡二叉树中依次插入n个结点,请输出最终的平衡二叉树。

要求实现平衡二叉树,不可以使用各类库函数。 AVL代码参考模板:

参考书本

Input

第一行输入测试数据组数t; 每组测试数据,第一行输入结点数n, 第二行输入n个结点值。

Output

对每组测试数据,按中序遍历的顺序输出树中,结点值及平衡因子(测试数据没有空树),即结点值:平衡因子,不同结点之间间隔一个空格。

Sample

#0

Input

Copy

8
3
64 5 1
3
64 5 13
6
64 78 5 1 13 15
6
64 78 5 1 13 10
3
64 78 100
3
64 80 70
6
64 30 80 90 70 68
6
64 30 80 90 70 75
Output

Copy

1:0 5:0 64:0
5:0 13:0 64:0
1:0 5:1 13:0 15:0 64:0 78:0
1:0 5:0 10:0 13:0 64:-1 78:0
64:0 78:0 100:0
64:0 70:0 80:0
30:0 64:0 68:0 70:0 80:-1 90:0
30:0 64:1 70:0 75:0 80:0 90:0
#include <iostream>
using namespace std;

#define LH 1  // 左高
#define EH 0  // 等高
#define RH -1 // 右高

class BiNode
{
public:
  int key; // 关键值
  int bf;  // 平衡因子
  BiNode *lChild, *rChild;
  BiNode(int kValue, int bValue)
  {

    key = kValue;
    bf = bValue;
    lChild = NULL;
    rChild = NULL;
  }

  ~BiNode()
  {
    key = 0;
    bf = 0;
    lChild = NULL;
    rChild = NULL;
  }
};

// 二叉排序树
class BST
{
private:
  BiNode *root; // 根结点指针
  void rRotate(BiNode *&p);
  void lRotate(BiNode *&p);
  void leftBalance(BiNode *&t);
  void rightBalance(BiNode *&t);
  int insertAVL(BiNode *&t, int key, bool &taller); // 插入元素并做平衡处理
  void inOrder(BiNode *p);

public:
  BST();
  void insertAVL(int key); // 二叉排序树插入元素
  ~BST();
  void inOrder(); // 中序遍历
};

// 以p为根的二叉排序树作右旋处理
void BST::rRotate(BiNode *&p)
{
  BiNode *lc = p->lChild;
  p->lChild = lc->rChild;
  lc->rChild = p;
  p = lc;
}

// 以p为根的二叉排序树作左旋处理
void BST::lRotate(BiNode *&p)
{
  BiNode *rc = p->rChild;
  p->rChild = rc->lChild;
  rc->lChild = p;
  p = rc;
}

// t为根的二叉排序树作左平衡旋转处理
void BST::leftBalance(BiNode *&t)
{
  BiNode *lc = t->lChild;
  switch (lc->bf)
  {
  case LH:
    t->bf = lc->bf = EH;
    rRotate(t);
    break;
  case RH:
    BiNode *rd = lc->rChild;
    switch (rd->bf)
    {
    case LH:
      t->bf = RH;
      lc->bf = EH;
      break;
    case EH:
      t->bf = lc->bf = EH;
      break;
    case RH:
      t->bf = EH;
      lc->bf = LH;
      break;
    }
    rd->bf = EH;
    lRotate(t->lChild);
    rRotate(t);
    break;
  }
}

// t为根的二叉排序树作右平衡旋转处理
void BST::rightBalance(BiNode *&t){
  BiNode *rc = t->rChild;
  switch (rc->bf)
  {
  case RH:
    t->bf = rc->bf = EH;
    lRotate(t);
    break;
  case LH:
    BiNode *ld = rc->lChild;
    switch (ld->bf)
    {
    case RH:
      t->bf = LH;
      rc->bf = EH;
      break;
    case EH:
      t->bf = rc->bf = EH;
      break;
    case LH:
      t->bf = EH;
      rc->bf = RH;
      break;
    }
    ld->bf = EH;
    rRotate(t->rChild);
    lRotate(t);
    break;
  }
}

int BST::insertAVL(BiNode *&t, int key, bool &taller)
{
  if (!t)
  {
    t = new BiNode(key, EH);
    taller = true;
  }
  else
  {
    if (key == t->key)
    {
      taller = false;
      return 0; 
    }
    if (key < t->key)
    {
      if (!insertAVL(t->lChild, key, taller))
        return 0;
      if (taller)
      {
        switch (t->bf)
        {
        case LH:
          leftBalance(t);
          taller = false;
          break;
        case EH:
          t->bf = LH;
          break;
        case RH:
          t->bf = EH;
          taller = false;
          break;
        }
      }
    }
    else
    {
      if (!insertAVL(t->rChild, key, taller))
        return 0;
      if (taller)
      {
        switch (t->bf)
        {
        case LH:
          t->bf = EH;
          taller = false;
          break;
        case EH:
          t->bf = RH;
          break;
        case RH:
          rightBalance(t);
          taller = false;
          break;
        }
      }
    }
  }
  return 1;
}

void BST::inOrder(BiNode *p)
{
  if (p)
  {
    inOrder(p->lChild);
    cout << p->key << ':' << p->bf << ' ';
    inOrder(p->rChild);
  }

  return;
}

// 二叉排序树初始化
BST::BST()
{
  root = NULL;
}

BST::~BST()
{
  root = NULL;
}

// 插入元素并作平衡处理
void BST::insertAVL(int key)
{
  bool taller = false;
  insertAVL(root, key, taller);
}

// 中序遍历
void BST::inOrder()
{
  inOrder(root);
}

int main(void)
{
  int t;
  cin >> t;
  while (t--)
  {
    // 构建二叉平衡树,并在插入元素时做平衡处理
    int n, elem;
    cin >> n;
    BST tree;
    while (n--)
    {
      cin >> elem;
      tree.insertAVL(elem);
    }
    tree.inOrder();
    cout << endl;
  }

  return 0;
}

哈希查找

DS哈希查找—二次探测再散列

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 49 Solved: 14

Description

定义哈希函数为H(key) = key%11。输入表长(大于、等于11),输入关键字集合,用二次探测再散列构建哈希表,并查找给定关键字。

Input

测试数据组数

每组测试数据格式如下:

哈希表长 ,关键字个数

然后为查找次数

待查关键字.

Output

对每组测试数据,输出以下信息:

构造的哈希表信息,数组中没有关键字的位置输出NULL

对k个待查关键字,分别输出:

0或1(0—不成功,1—成功)、比较次数、查找成功的位置(从1开始)

Input

Copy

1
12 10
22 19 21 8 9 30 33 4 41 13
4
22
15
30
41
Output
22 9 13 NULL 4 41 NULL 30 19 8 21 33
1 1 1
0 3
1 3 8
1 6 6
#include <iostream>
#include <vector>
using namespace std;

int hashmod(int key) {
    return key % 11;
}

int rehash(int key, vector<int>& hashTable, int m) {
    int temp = hashmod(key);
    int num = 1;
    int pos = 0;
    while (true) {
        if (hashTable[temp] == -1) {
            return temp;
        }
        if (!(pos % 2)) {
            temp = (hashmod(key) + num * num) % m;
            pos++;
        } else {
            temp = (hashmod(key) - num * num + 1000 * m) % m;
            pos++;
            num++;
        }
    }
}

void searchKey(int key, vector<int>& hashTable, int m) {
    int temp = hashmod(key);
    int num = 1;
    int pos = 0;
    int comparisons = 1;

    while (true) {
        if (hashTable[temp] == key) {
            cout << 1 << " " << comparisons << " " << temp + 1 << endl;
            break;
        }
        if (hashTable[temp] == -1 || comparisons >= m) {
            cout << 0 << " " << comparisons << endl;
            break;
        }
        if (!(pos % 2)) {
            temp = (hashmod(key) + num * num) % m;
            pos++;
        } else {
            temp = (hashmod(key) - num * num + 1000 * m) % m;
            pos++;
            num++;
        }
        comparisons++;
    }
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        int m, n;
        cin >> m >> n;
        vector<int> hashTable(m, -1);
        for (int i = 0; i < n; i++) {
            int key;
            cin >> key;
            int temp = rehash(key, hashTable, m);
            hashTable[temp] = key;
        }
        for (int i = 0; i < m; i++) {
            if (hashTable[i] != -1)
                cout << hashTable[i] << " ";
            else
                cout << "NULL ";
        }
        cout << endl;

        int ct;
        cin >> ct;
        while (ct--) {
            int key;
            cin >> key;
            searchKey(key, hashTable, m);
        }
    }
    return 0;
}

/**********************************************************************
	Problem: 1038
	Language: C++
	Result: AC
	Time:34 ms
	Memory:2220 kb
**********************************************************************/

DS哈希查找–链地址法

Time Limit: 1 Sec Memory Limit: 128 Mb Submitted: 14 Solved: 6

Description

给出一个数据序列,建立哈希表,采用求余法作为哈希函数,模数为11,哈希冲突用链地址法和表头插入

如果首次查找失败,就把数据插入到相应的位置中

实现哈希查找功能

Input

第一行输入n,表示有n个数据

第二行输入n个数据,都是自然数且互不相同,数据之间用空格隔开

第三行输入t,表示要查找t个数据

从第四行起,每行输入一个要查找的数据,都是正整数

Output

每行输出对应数据的查找结果

Input

Copy

6
11 23 39 48 75 62
6
39
52
52
63
63
52
Output

Copy

6 1
error
8 1
error
8 1
8 2
#include <iostream>
#include <vector>
#include <list>
using namespace std;

int main()
{
    int n;
    while (cin >> n)
    {
        vector<list<int>> hashTable(11);
        for (int i = 0; i < n; i++)
        {
            int num;
            cin >> num;
            hashTable[num % 11].push_front(num);
        }
        int t;
        cin >> t;
        while (t--)
        {
            int num;
            cin >> num;
            int hashKey = num % 11;
            int count = 1;
            for (auto it = hashTable[hashKey].begin(); it != hashTable[hashKey].end(); it++, count++)
            {
                if (*it == num)
                {
                    cout << hashKey << " " << count << endl;
                    break;
                }
            }
            if (count > hashTable[hashKey].size())
            {
                cout << "error" << endl;
                hashTable[hashKey].push_front(num);
            }
        }
    }
    return 0;
}
/**********************************************************************
	Problem: 1034
	Language: C++
	Result: AC
	Time:37 ms
	Memory:2220 kb
**********************************************************************/

  • 25
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

发愤图强想做全栈的小陈

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值