#include using namespace std; #pragma region SPFA算法模板 // 最短路径——SPFA算法 // 最大值 // https://blog.csdn.net/jiange_zh/article/details/50198097 /** 如果我们想要将某个数组清零,我们通常会使用memset(a,0,sizeof(a)),方便又高效,但是当我们想将某个数组全部赋值为无穷大时, 就不能使用memset函数而得自己写循环了,因为memset是按字节操作的,它能够对数组清零是因为0的每个字节都是0(一般我们只有赋值为-1 和0的时候才使用它)。现在好了,如果我们将无穷大设为0x3f3f3f3f,那么奇迹就发生了,0x3f3f3f3f的每个字节都是0x3f!所以要把一段 内存全部置为无穷大,我们只需要memset(a,0x3f,sizeof(a))。所以在通常的场合下,0x3f3f3f3f真的是一个非常棒的选择! */ const int INF = 0x3f3f3f3f; // https://www.cnblogs.com/xzxl/p/7246918.html int matrix[100][100]; //邻接矩阵 bool visited[100]; //标记数组 int dist[100]; //源点到顶点i的最短距离 int path[100]; //记录最短路的路径 int enqueue_num[100]; //记录入队次数 int vertex_num; //顶点数 int edge_num; //边数 int source; //源点 bool SPFA() { memset(visited, 0, sizeof(visited)); memset(enqueue_num, 0, sizeof(enqueue_num)); for (int i = 1; i <= vertex_num; i++) { dist[i] = INF; path[i] = source; } queue Q; Q.push(source); dist[source] = 0; visited[source] = 1; enqueue_num[source]++; while (!Q.empty()) { int u = Q.front(); Q.pop(); visited[u] = 0; for (int v = 1; v <= vertex_num; v++) { if (matrix[u][v] != INF) //u与v直接邻接 { if (dist[u] + matrix[u][v] < dist[v]) { dist[v] = dist[u] + matrix[u][v]; path[v] = u; if (!visited[v]) { Q.push(v); enqueue_num[v]++; if (enqueue_num[v] >= vertex_num) return false; visited[v] = 1; } } } } } return true; } void Print() { for (int i = 1; i <= vertex_num; i++) { if (i != source) { int p = i; stack s; cout << "顶点 " << source << " 到顶点 " << p << " 的最短路径是: "; while (source != p) //路径顺序是逆向的,所以先保存到栈 { s.push(p); p = path[p]; } cout << source; while (!s.empty()) //依次从栈中取出的才是正序路径 { cout << "--" << s.top(); s.pop(); } cout << " 最短路径长度是:" << dist[i] << endl; } } } #pragma endregion SPFA算法模板 int main() { //录入参数文件 freopen("../1411.txt", "r", stdin); int n; // 奶牛数,牧场数,牧场间道路数 cin >> n >> vertex_num >> edge_num; //每个牧场的奶牛数量 vector naiNiuCountArr(vertex_num + 1); //这个容器开始时有 vertex_num + 1 个元素,它们的默认初始值都为 0。 for (int i = 1; i <= n; ++i) { int d; cin >> d; naiNiuCountArr[d]++; } //初始为两个节点之间为无穷大 for (int i = 1; i <= vertex_num; i++) for (int j = 1; j <= vertex_num; j++) matrix[i][j] = INF; //初始化matrix数组 //读入edge_num条边的信息 for (int i = 1; i <= edge_num; ++i) { int a, b, c; cin >> a >> b >> c; matrix[a][b] = c; //双向,表示是无向图 matrix[b][a] = c; //双向,表示是无向图 } //遍历每一个顶点,假设将糖放在这个顶点上 int minPath = INF; int point_vertex_num; for (int i = 1; i <= vertex_num; ++i) { //每个顶点都算一次到各个其它顶点的距离 source = i; SPFA(); //Print(); //假设从source节点出发的话,那么需要所有奶牛共同加在一起走的最小路径和 int allPath = 0; for (int j = 1; j <= vertex_num; j++) { allPath += dist[j] * naiNiuCountArr[j]; } //挑出最少的那个节点路径和 if (minPath > allPath) { minPath = allPath; //记录是哪个节点时发生了这个变化 point_vertex_num = source; } } // cout << minPath << " " << point_vertex_num << endl; cout << minPath << endl; //关闭文件 fclose(stdin); return 0; }