深圳大学计软《数据结构》实验10--图的最小生成树以及图连通性的应用

问题 A: DS图—最小生成树

题目描述

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

输入

顶点数n

n个顶点

边数m

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

Prim算法的起点v

输出

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

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

样例输入

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

样例输出

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

AC代码

#include<bits/stdc++.h>
using namespace std;

const int MAXWEIGHT = 9999999;

struct Node {
	int v1, v2, weight;
};

bool cmp(const Node& a, const Node& b) {
	return a.weight < b.weight;
}

class Map {
	int VertexNum;
	string* Vertex;
	int** AdjMatrix;
	Node* node1, * node2;
	int GetIndex(string ch) {
		for (int i = 0; i < VertexNum; i++) {
			if (ch == Vertex[i])
				return i;
		}
		return -1;
	}

public:
	Map() {
		cin >> VertexNum;
		Vertex = new string[VertexNum];
		node1 = new Node[VertexNum - 1];
		AdjMatrix = new int* [VertexNum];
		for (int i = 0; i < VertexNum; i++) {
			cin >> Vertex[i];
			AdjMatrix[i] = new int[VertexNum];
			for (int j = 0; j < VertexNum; j++)
				AdjMatrix[i][j] = MAXWEIGHT;
		}
	}


	void CreateMap() {
		int edge, v1, v2, weight;
		string s1, s2;

		cin >> edge;
		node2 = new Node[edge];

		for (int i = 0; i < edge; i++) {
			cin >> s1 >> s2 >> weight;

			v1 = GetIndex(s1);
			v2 = GetIndex(s2);
			AdjMatrix[v1][v2] = weight;
			AdjMatrix[v2][v1] = weight;

			node2[i].v1 = v1 < v2 ? v1 : v2;
			node2[i].v2 = v1 > v2 ? v1 : v2;
			node2[i].weight = weight;
		}
		sort(node2, node2 + edge, cmp);
	}

	void Prim(string start) {
		int p1, p2, max, sum = 0, k = 0;
		Node* temp = new Node[VertexNum];

		p1 = GetIndex(start);
		for (int i = 0; i < VertexNum; i++) {
			temp[i].v1 = p1;
			temp[i].weight = AdjMatrix[p1][i];
		}
		temp[p1].weight = 0;

		for (int i = 1; i < VertexNum; i++) {
			max = MAXWEIGHT;
			for (int j = 0; j < VertexNum; j++) {
				if (temp[j].weight && temp[j].weight < max) {
					max = temp[j].weight;
					p2 = j;
				}
			}

			sum += max;
			node1[k].v1 = temp[p2].v1;
			node1[k].v2 = p2;
			node1[k].weight = max;
			k++;

			for (int j = 0; j < VertexNum; j++) {
				if (temp[j].weight && temp[j].weight > AdjMatrix[p2][j]) {
					temp[j].weight = AdjMatrix[p2][j];
					temp[j].v1 = p2;
				}
			}

			temp[p2].weight = 0;
		}

		cout << sum << endl;
		cout << "prim:" << endl;
		for (int i = 0; i < VertexNum - 1; i++)
			cout << Vertex[node1[i].v1] << " " << Vertex[node1[i].v2] << " " << node1[i].weight << endl;

		delete[] temp;
	}


	void Kruskal() {
		puts("kruskal:");
		int  k = 0, cnt = 0;
		int* v = new int[VertexNum];
		for (int i = 0; i < VertexNum; i++)
			v[i] = i;

		while (VertexNum - 1 != cnt) {
			int p1 = node2[k].v1;
			int p2 = node2[k].v2;
			if (v[p1] != v[p2]) {
				cnt++;
				cout << Vertex[p1] << " " << Vertex[p2] << " " << node2[k].weight << endl;
				int q1 = min(v[p1], v[p2]);
				int q2 = max(v[p1], v[p2]);
				for (int i = 0; i < VertexNum; i++) {
					if (v[i] != q1)
						continue;
					v[i] = q2;
				}
			}
			k++;
		}
		delete[] v;
	}

};

int main() {
	Map m;
	m.CreateMap();
	string start;
	cin >> start;
	m.Prim(start);
	m.Kruskal();
	return 0;
}

问题 B: 道路建设 (Ver. I)

题目描述

有N个村庄,编号从1到N,你应该建造一些道路,使每个村庄都可以相互连接。

两个村A和B是相连的,当且仅当A和B之间有一条道路,或者存在一个村C使得在A和C之间有一条道路,并且C和B相连。

现在一些村庄之间已经有一些道路,你的任务就是修建一些道路,使所有村庄都连通起来,并且所有道路的长度总和是最小的。

输入

测试数据有多组

第一行是整数N(3 <= N <= 100),代表村庄的数量。 然后是N行,其中第i行包含N个整数,这些N个整数中的第j个是村庄i和村庄j之间的距离(距离是[1,1000]内的整数)。

然后是整数Q(0 <= Q <= N *(N + 1)/ 2),接下来是Q行,每行包含两个整数a和b(1 <= a <b <= N),代表着村庄a和村庄b之间的道路已经建成。

输出

对于每组测试数据

输出一个整数,表示要构建的道路的长度总和最小值

样例输入

3
0 990 692
990 0 179
692 179 0
1
1 2

样例输出

179

AC代码

#include<bits/stdc++.h>
using namespace std;

const int MAXWEIGHT = 9999999;

struct Node {
	int v1, v2, weight;
};

bool cmp(const Node& a, const Node& b) {
	return a.weight < b.weight;
}

class Map {
	int VertexNum;
	int** AdjMatrix;
	int* visited;
public:
	Map(int VertexNum = 0) :VertexNum(VertexNum){
		visited = new int[VertexNum];
		AdjMatrix = new int* [VertexNum];
		for (int i = 0; i < VertexNum; i++) {
			AdjMatrix[i] = new int[VertexNum];
			visited[i] = 0;
			for (int j = 0; j < VertexNum; j++)
				cin >> AdjMatrix[i][j];
		}
	}

	int prim() {
		int intdex, _max;
		int sum = 0;
		visited[0] = 1;
		for (int i = 0; i < VertexNum - 1; i++)
		{
			_max = MAXWEIGHT;
			for (int j = 0; j < VertexNum; j++)
				for (int k = 0; k < VertexNum; k++)
					if (visited[j] && !visited[k] && AdjMatrix[j][k] < _max)
					{
						intdex = k;
						_max = AdjMatrix[j][k];
					}
			visited[intdex] = 1;
			sum += _max;
		}
		return sum;
	}

	void setPath(int i, int j) { AdjMatrix[i][j] = AdjMatrix[j][i] = 0; }
};


	//	void Kruskal() {
	//		puts("kruskal:");
	//		int  k = 0, cnt = 0;
	//		int* v = new int[VertexNum];
	//		for (int i = 0; i < VertexNum; i++)
	//			v[i] = i;
	//
	//		while (VertexNum - 1 != cnt) {
	//			int p1 = node2[k].v1;
	//			int p2 = node2[k].v2;
	//			if (v[p1] != v[p2]) {
	//				cnt++;
	//				cout << Vertex[p1] << " " << Vertex[p2] << " " << node2[k].weight << endl;
	//				int q1 = min(v[p1], v[p2]);
	//				int q2 = max(v[p1], v[p2]);
	//				for (int i = 0; i < VertexNum; i++) {
	//					if (v[i] != q1)
	//						continue;
	//					v[i] = q2;
	//				}
	//			}
	//			k++;
	//		}
	//		delete[] v;
	//	}
	//
	//};

	int main() {
		int len;
		while (cin>>len) {
			Map m(len);
			int n;
			cin >> n;
			while (n--) {
				int u, v;
				cin >> u >> v;
				m.setPath(u - 1, v - 1);
			}
			cout << m.prim() << endl;
		}
		return 0;
	}

问题 C: 图的应用之——图的连通

题目描述

给定一个图的邻接矩阵,请判断该图是否是连通图。连通图:任意两个顶点之间都有路径。
–程序要求–
若使用C++只能include一个头文件iostream;若使用C语言只能include一个头文件stdio
程序中若include多过一个头文件,不看代码,作0分处理
不允许使用第三方对象或函数实现本题的要求

输入

第1行输入一个整数k,表示有k个测试数据
第2行输入一个整数n,表示有n个结点
从第3行起到第n+2行输入一个邻接矩阵,其中Matrix[i,j]=1表示第i,j个结点之间有边,否则不存在边。
接下来是第2到第k个测试数据的结点数和邻接矩阵

输出

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

样例输入

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

样例输出

Yes
No

AC代码

#include<iostream>
using namespace std;

class Map {
	int VertexNum;
	bool* visited;
	int** Vertex;
	int cnt;
	void dfs(int cur_index) {
		cnt++;
		visited[cur_index] = true;
		for (int i = VertexNum - 1; i >= 0; i--)
			if (Vertex[cur_index][i] && !visited[i])
				dfs(i);
	}
public:
	Map() {
		cin >> VertexNum;
		visited = new bool[VertexNum];
		for (int i = 0; i < VertexNum; i++)
			visited[i] = false;
		Vertex = new int* [VertexNum];
		for (int i = 0; i < VertexNum; i++)
			Vertex[i] = new int[VertexNum];
		for (int i = 0; i < VertexNum; i++)
			for (int j = 0; j < VertexNum; j++)
				cin >> Vertex[i][j];
	}

	void dfs() {
		for (int i = 0; i < VertexNum; i++) {
			cnt = 0;
			dfs(i);
			if (cnt != VertexNum)
			{
				puts("No");
				return;
			}
			for (int j = 0; j < VertexNum; j++)
				visited[j] = false;
		}
		puts("Yes");
	}


	~Map() {
		delete[] visited;
		for (int i = 0; i < VertexNum; i++)
			delete[] Vertex[i];
		delete[] Vertex;
	}
};

int main() {
	int n;
	cin >> n;
	while (n--) {
		Map m;
		m.dfs();
	}
	return 0;
}

问题 D: 图的顶点可达闭包

题目描述

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

输入

第1行顶点个数n

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

输出

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

样例输入

4
0 1 0 1
0 0 1 0
0 0 0 0
0 0 0 0

样例输出

0 1 1 1
0 0 1 0
0 0 0 0
0 0 0 0

AC代码

#include<bits/stdc++.h>
using namespace std;

class Map {
    int VertexNum; 
    int* Vertex;  
    int** p, ** s; 
public:
    Map() {
        cin >> VertexNum;
        Vertex = new int[VertexNum];
        for (int i = 0; i < VertexNum; i++)
            Vertex[i] = 0;
        p = new int* [VertexNum];
        s = new int* [VertexNum];
        for (int i = 0; i < VertexNum; i++) {
            p[i] = new int[VertexNum];
            s[i] = new int[VertexNum];
        }
        for (int i = 0; i < VertexNum; i++)
            for (int j = 0; j < VertexNum; j++) {
                cin >> p[i][j];
                s[i][j] = 0;
            }
    }

    void dfs(int cur_index) {
        Vertex[cur_index] = 1;
        for (int i = 0; i < VertexNum; i++) {
            if (p[cur_index][i] && !Vertex[i]) {
                dfs(i);
            }
        }
    }

    void dfs() {
        for (int i = 0; i < VertexNum; i++) {
            dfs(i);
            for (int j = 0; j < VertexNum; j++) { 
                if (j != i)
                    s[i][j] = Vertex[j];
                else
                {
                    for (int k = 0; k < VertexNum; k++)
                        if (Vertex[k] == 1 && p[k][i] == 1) {
                            s[i][i] = 1;
                            break;
                        }
                }
            }
            for (int t = 0; t < VertexNum; t++)
                Vertex[t] = 0;
        }
    }

    void print() {
        int i, j;
        for (i = 0; i < VertexNum; i++) {
            for (j = 0; j < VertexNum - 1; j++)
                cout << s[i][j] << " ";
            cout << s[i][j] << endl;
        }
    }


    ~Map() {
        for (int i = 0; i < VertexNum; i++) {
            delete[] p[i];
            delete[] s[i];
        }
        delete[] p;
        delete[] s;
        delete[] Vertex;
    }
};

int main() {
    Map m;
    m.dfs();
    m.print();
    return 0;
}

问题 E: 货币套汇

题目描述

套汇是指利用货币汇兑率的差异将一个单位的某种货币转换为大于一个单位的同种货币。例如,假定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

输入

第一行:测试数据组数

每组测试数据格式为:

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

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

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

输出

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

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

样例输入

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

样例输出

YES
NO

AC代码

#include<bits/stdc++.h>
using namespace std;

class Map {
	int VertexNum;
	string* Vertex;
	int* visited;
	float** AdjMatrix;
	int* r;
	int count;
	void dfs(int index) {
		visited[index] = 1;
		r[count] = index;
		count++;
		for (int i = 0; i < VertexNum; i++)
			if (AdjMatrix[index][i] && !visited[i])
				dfs(i);
	}
	int getIndex(string s) {
		for (int i = VertexNum - 1; i >= 0; --i)
			if (Vertex[i] == s)
				return i;
	}
public:
	/*void print() {
		for (int i = 0; i < VertexNum; i++)
		{
			for (int j = 0; j < VertexNum; j++)
			{
				if (j)cout << " ";
				cout << Vertex[i][j];
			}cout << endl;
		}
	}*/
	Map() {
		cin >> VertexNum;
		visited = new int[VertexNum];
		Vertex = new string[VertexNum];
		r = new int[VertexNum];
		for (int i = 0; i < VertexNum; i++)
			visited[i] = r[i] = 0;
		AdjMatrix = new float* [VertexNum];
		for (int i = 0; i < VertexNum; i++)
			AdjMatrix[i] = new float[VertexNum];
		for (int i = 0; i < VertexNum; i++) {
			for (int j = 0; j < VertexNum; j++) {
				AdjMatrix[i][j] = 0;
				if (i == j)
					AdjMatrix[i][j] = 1;
			}
		}
		int edge_num;
		cin >> edge_num;
		for (int i = 0; i < VertexNum; i++)
			cin >> Vertex[i];

		for (int i = 0; i < edge_num; i++) {
			string s1, s2;
			float t;
			cin >> s1 >> t >> s2;
			AdjMatrix[getIndex(s1)][getIndex(s2)] = t;
		}
	}

	

	//void dfs(int index) {
	//	visited[index] = 1;
	//	r[count] = index;
	//	count++;
	//	for (int i = 0; i < VertexNum; i++) {
	//		if (AdjMatrix[index][i] && !visited[i]) {
	//			dfs(i);
	//		}
	//	}
	//}

	void dfs() {
		for (int i = 0; i < VertexNum; i++) {
			count = 0;
			dfs(i);

			int j;
			for (int k = 1; k < count; k++)
				if (AdjMatrix[r[k]][i] != 0) {
					float result = 1.0;
					for (j = 0; j < k; j++) {
						result *= AdjMatrix[r[j]][r[j + 1]];
					}
					result *= AdjMatrix[r[j]][r[0]];
					if (result > 1) {
						cout << "YES" << endl;
						return;
					}
				}

			for (int t = VertexNum - 1; t >= 0; --t)
				visited[t] = r[t] = 0;
		}
		cout << "NO" << endl;
	}

};

int main() {
	int n;
	cin >> n;
	while (n--) {
		Map m;
		//m.print();
		m.dfs();
	}
	return 0;
}
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

曹无悔

请支持我的梦想!

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

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

打赏作者

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

抵扣说明:

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

余额充值