油管铺设
作者: 冯向阳
时间限制: 1s
章节: 课程设计
问题描述
八口海上油井相互间距离如下表所示(样例1数据)。其中1号井离海边距离最近,为5.6海里。现计划从海岸铺设油管将各油井连接起来,如何设计才能使得油管的长度最短。(为便于检修,油管只允许在油井处分叉)。
提示:
基于最小生成树思想解决实际问题。
输入说明
第一行:图的类型
第二行:结点数
第三行:结点集
第四行:无边标记
第五行:边数
第六行:边集
第七行:权集
第八行:起始结点序号u
第九行:1号井距离海边的距离
输出说明
第一行:油管最短长度
#include <iostream>
#include <string>
#include <queue>
#include <vector>
using namespace std;
template<class TypeOfEdge>
struct edgeNode
{
size_t data;
TypeOfEdge weight;
edgeNode<TypeOfEdge>* next;
edgeNode(const size_t& d, const TypeOfEdge& w, edgeNode<TypeOfEdge>* ptr = nullptr)
{
data = d;
weight = w;
next = ptr;
}
};
template<class TypeOfVer, class TypeOfEdge>
struct verNode
{
TypeOfVer ver;
edgeNode<TypeOfEdge>* head;
verNode(edgeNode<TypeOfEdge>* h = nullptr)
{
head = h;
}
};
template <class TypeOfVer, class TypeOfEdge>
class adjlist_graph
{
private:
int Vers; // Number of vertices
verNode<TypeOfVer, TypeOfEdge>* verList;
string GraphKind;
//广度优先遍历
void BFS_Util(queue<int>& q, vector<bool>& visited)
{
if (q.empty())
return;
int u = q.front();
cout << verList[u].ver;
q.pop();
edgeNode<TypeOfEdge>* curr = verList[u].head;
while (curr != nullptr)
{
size_t v = curr->data;
if (!visited[v])
{
q.push(v);
visited[v] = true;
}
curr = curr->next;
}
if (!q.empty())
{
cout << "->";
BFS_Util(q, visited);
}
}
public:
adjlist_graph(const string& kd, int vSize, const TypeOfVer d[]) : Vers(vSize), GraphKind(kd)
{
verList = new verNode<TypeOfVer, TypeOfEdge>[Vers];
for (int i = 0; i < Vers; ++i)
{
verList[i].ver = d[i];
}
}
adjlist_graph(const string& kd, int vSize, int eSize, const TypeOfVer d[], int** e) : Vers(vSize), GraphKind(kd)
{
verList = new verNode<TypeOfVer, TypeOfEdge>[Vers];
for (int i = 0; i < Vers; ++i)
{
verList[i].ver = d[i];
verList[i].head = nullptr;
}
for (int i = 0; i < eSize; ++i)
{
int u = e[i][0];
int v = e[i][1];
edgeNode<TypeOfEdge>* newNode = new edgeNode<TypeOfEdge>(v, 0, verList[u].head);
verList[u].head = newNode;
newNode = new edgeNode<TypeOfEdge>(u, 0, verList[v].head);
verList[v].head = newNode;
}
}
adjlist_graph(const string& kd, int vSize, int eSize, const TypeOfVer d[], int** e, const TypeOfEdge w[]) : Vers(vSize), GraphKind(kd)
{
verList = new verNode<TypeOfVer, TypeOfEdge>[Vers];
for (int i = 0; i < Vers; ++i)
{
verList[i].ver = d[i];
verList[i].head = nullptr;
}
for (int k = 0; k < eSize; ++k)
{
int u = e[k][0];
int v = e[k][1];
TypeOfEdge weight = w[k];
if (GraphKind == "DG" || GraphKind == "DN")
{
edgeNode<TypeOfEdge>* newNode = new edgeNode<TypeOfEdge>(v, weight, verList[u].head);
verList[u].head = newNode;
}
else
{
edgeNode<TypeOfEdge>* newNode = new edgeNode<TypeOfEdge>(v, weight, verList[u].head);
verList[u].head = newNode;
newNode = new edgeNode<TypeOfEdge>(u, weight, verList[v].head);
verList[v].head = newNode;
}
}
}
~adjlist_graph()
{
for (int i = 0; i < Vers; ++i)
{
edgeNode<TypeOfEdge>* curr = verList[i].head;
while (curr != nullptr)
{
edgeNode<TypeOfEdge>* temp = curr;
curr = curr->next;
delete temp;
}
}
delete[] verList;
}
// 获取顶点的入度
int Get_InDegree(int u, string& kd)
{
if (u < 0 || u >= Vers || kd == "UDG" || kd == "UDN")
return -1;
int inDegree = 0;
for (int i = 0; i < Vers; ++i)
{
edgeNode<TypeOfEdge>* curr = verList[i].head;
while (curr != nullptr)
{
if (curr->data == u)
++inDegree;
curr = curr->next;
}
}
return inDegree;
}
//广度优先遍历
void BFS_Traverse(int u)
{
vector<bool> visited(Vers, false);
queue<int> q;
q.push(u);
visited[u] = true;
BFS_Util(q, visited);
}
//打印邻接表
void printAdjList()
{
for (int i = 0; i < Vers; ++i)
{
cout << verList[i].ver;
edgeNode<TypeOfEdge>* curr = verList[i].head;
while (curr != nullptr)
{
cout << "->" << curr->data;
curr = curr->next;
}
cout << endl;
}
}
//打印邻接矩阵
bool PrintMatrix()
{
cout << GraphKind << endl;
for (int i = 0; i < Vers; ++i)
{
cout << verList[i].ver;
if (i != Vers - 1)
cout << " ";
}
cout << endl;
return true;
}
//获取权值
bool GetWeight(int u, int v, TypeOfEdge& w);
//最小生成树
void MiniSpanTree_Prim(int u, TypeOfEdge signal,TypeOfEdge distance)
{
vector<int> adjvex(Vers, u);
vector<TypeOfEdge> lowcost(Vers, signal); // 初始化为signal,表示无穷大或未连接
vector<bool> visited(Vers, false);
visited[u] = true; // 标记u已访问
edgeNode<TypeOfEdge>* curr = verList[u].head;
while (curr != nullptr) // 初始化与u直接相连的顶点的lowcost
{
lowcost[curr->data] = curr->weight;
curr = curr->next;
}
for (int i = 1; i < Vers; ++i) // 循环n-1次,每次找到一个顶点加入生成树
{
TypeOfEdge min = signal;
int k = -1;
for (int j = 0; j < Vers; ++j)
{
if (!visited[j] && lowcost[j] < min)
{
min = lowcost[j];
k = j;
}
}
if (k == -1) break; // 如果没有找到合适的顶点,退出循环
visited[k] = true;
curr = verList[k].head; // 遍历k的邻接点
while (curr != nullptr) // 更新lowcost和adjvex
{
if (!visited[curr->data] && curr->weight < lowcost[curr->data])
{
lowcost[curr->data] = curr->weight;
adjvex[curr->data] = k;
}
curr = curr->next;
}
}
// 输出最小生成树的权值
TypeOfEdge total = distance;
for (int i = 0; i < Vers; ++i)
{
if (i != u && lowcost[i] != signal)
{
total += lowcost[i];
}
}
cout << total << endl;
}
};
//设置权值
template<class TypeOfVer, class TypeOfEdge>
bool adjlist_graph<TypeOfVer, TypeOfEdge>::GetWeight(int u, int v, TypeOfEdge& w)
{
if (u < 0 || u >= Vers || v < 0 || v >= Vers)
return false;
edgeNode<TypeOfEdge>* curr = verList[u].head;
while (curr != nullptr)
{
if (curr->data == v)
{
w = curr->weight;
return true;
}
curr = curr->next;
}
return false;
}
int main()
{
string graphType;
int n, m, count = 0;
cin >> graphType >> n;//图的类型和顶点数
string* verArr = new string[n];//顶点集
for (int i = 0; i < n; ++i)
{
cin >> verArr[i];
}
double signal;//无边标记
cin >> signal;
cin >> m;//边数
int** edgeArr = new int* [m];//边集
for (int i = 0; i < m; ++i)
{
edgeArr[i] = new int[2];
cin >> edgeArr[i][0] >> edgeArr[i][1];
}
double* weightArr = new double[m];//权值
for (int i = 0; i < m; ++i)
{
cin>> weightArr[i];
}
int start;//起始节点序号
cin >> start;
double distance;//最小距离;
cin >> distance;
adjlist_graph<string, double> graph(graphType, n, m, verArr, edgeArr, weightArr);
graph.MiniSpanTree_Prim(start,signal,distance);
// 释放动态内存
delete[] verArr;
for (int i = 0; i < m; ++i)
{
delete[] edgeArr[i];
}
delete[] edgeArr;
delete[] weightArr;
return 0;
}