按照要求自动生成无向/有向图(基于C++实现)

  • 最小连通子图生成算法
  • 程序的思路和伪代码
  • 主函数代码
  • 程序运行结果展示

本文内容是按照图的类型(随机有向图 无向连通图、节点个数N、边个数M、以及边的权值范围(float),来生成随机图。
其中无向图生成过程中,为了保证其连通关系,采用了从最小连通图(即两个节点)出发,逐步利用连接关系“吞并”其它连通图,最终得到一个最小连通子图,确保了生成的最终图的连通性,很具有学习意义。
详细代码我已经上传至码云:create_random_graph(基于VS2017)
生成的图信息可用Matlab显示出来,具体可参考我的博文:MATLAB读取csv文件显示有向/无向图和目标路径(用于路径搜索算法的展示)

最小连通子图生成算法

思路:

  1. 将N节点按照两个节点随机分成N/2个小组(N为奇数,最后一个小组为三个节点),分完之后,确定其连接关系(小组内相邻两节点之间生成边);
  2. 在现有的小组中随机挑选出两个小组,并在挑选出的小组中随机挑选一个节点作为连接节点,然后将两个小组连接(即编号小的小组吞并编号大的小组);
  3. 重复2,直到只有一个小组

具体实现:
设需要生成的图具有N个节点,则建立两个一维数组:
arr[N]:从1-N的随机序列,用来存储N个节点的序号
arr_id[N]:从1-N/2的顺序列,用来存储N个节点所分组的小组id

以输入N=11为例,一开始,两个数组分别为:

arr[0] arr[1] arr[2] arr[3] arr[4] arr[5] arr[6] arr[7] arr[8] arr[9] arr[10]
9 1 5 6 10 4 3 2 0 7 8
arr_id[0] arr_id[1] arr_id[2] arr_id[3] arr_id[4] arr_id[5] arr_id[6] arr_id[7] arr_id[8] arr_id[9] arr_id[10]
1 1 2 2 3 3 4 4 5 5 5

在arr_id数组中,可以看到arr数组中相邻两个为一个小组,为了确定小组内节点的连接关系,于是每一个小组都增加节点之间的边:
小组1:edge(9,1)
小组2:edge(5,6)
小组3:edge(10,4)
小组4:edge(3,2)
小组5:edge(0,7),edge(7,8)
这样就保证了所有小组内部的连通性,然后,对5个小组之间进行随机配对并连接:

  1. 选择小组2、小组3进行配对,并从小组2中挑选出节点5,从小组3中挑选出节点4,生成边edge(5,4),连接小组2和小组3,且连接过后,小组2吞并小组3,此时两个数组为:
arr[0] arr[1] arr[2] arr[3] arr[4] arr[5] arr[6] arr[7] arr[8] arr[9] arr[10]
9 1 5 6 10 4 3 2 0 7 8
arr_id[0] arr_id[1] arr_id[2] arr_id[3] arr_id[4] arr_id[5] arr_id[6] arr_id[7] arr_id[8] arr_id[9] arr_id[10]
1 1 2 2 2 2 4 4 5 5 5

此时小组数为4>1,继续;

  1. 选择小组4、小组5进行配对,并从小组4中挑选出节点2,从小组5中挑选出节点7,生成边edge(2,7),连接小组4和小组5,且连接过后,小组4吞并小组5,此时两个数组为:
arr[0] arr[1] arr[2] arr[3] arr[4] arr[5] arr[6] arr[7] arr[8] arr[9] arr[10]
9 1 5 6 10 4 3 2 0 7 8
arr_id[0] arr_id[1] arr_id[2] arr_id[3] arr_id[4] arr_id[5] arr_id[6] arr_id[7] arr_id[8] arr_id[9] arr_id[10]
1 1 2 2 2 2 4 4 4 4 4

此时小组数为3>1,继续;

  1. 选择小组2、小组4进行配对,并从小组2中挑选出节点6,从小组4中挑选出节点8,生成边edge(6,8),连接小组2和小组4,且连接过后,小组2吞并小组4,此时两个数组为:
arr[0] arr[1] arr[2] arr[3] arr[4] arr[5] arr[6] arr[7] arr[8] arr[9] arr[10]
9 1 5 6 10 4 3 2 0 7 8
arr_id[0] arr_id[1] arr_id[2] arr_id[3] arr_id[4] arr_id[5] arr_id[6] arr_id[7] arr_id[8] arr_id[9] arr_id[10]
1 1 2 2 2 2 2 2 2 2 2

此时小组数为2>1,继续;

  1. 选择小组2、小组1进行配对,并从小组2中挑选出节点4,从小组1中挑选出节点9,生成边edge(4,9),连接小组2和小组1,且连接过后,小组1吞并小组2,此时两个数组为:
arr[0] arr[1] arr[2] arr[3] arr[4] arr[5] arr[6] arr[7] arr[8] arr[9] arr[10]
9 1 5 6 10 4 3 2 0 7 8
arr_id[0] arr_id[1] arr_id[2] arr_id[3] arr_id[4] arr_id[5] arr_id[6] arr_id[7] arr_id[8] arr_id[9] arr_id[10]
1 1 1 1 1 1 1 1 1 1 1

此时小组数为1=1,结束。

算法代码

         //step1 //生成一个连通子图,N-1条边         //1.1首先随机分组//一个记录节点小组下标的数组int  *arr_id = new int[NodeCounts];for (int i = 0; i < NodeCounts; i++)arr_id[i] = 0;//小组idint id = 0;//产生一个随机节点序列int *arr = new int[NodeCounts];for (int i = 0; i < NodeCounts; i++)arr[i] = 0;int count = 0;srand(time(NULL));while (count < NodeCounts){int val = rand() % NodeCounts;if (!arr[val]){//printf("%d ", val);arr[val] = count + 1;++count;}}/*for (int i = 0; i < NodeCounts; i++)printf("%d ", arr[i]);*///1.2根据随机序列arr,两个节点一组进行分组int node1 = 1, node2 = 1;double len = 0.0;for (int i = 0; i <= NodeCounts - 2; i=i+2){//分组,标记分组号id++;arr_id[i] = id;arr_id[i+1] = id;             //添加相应边node1 = arr[i] - 1;node2 = arr[i + 1] - 1;len = rand() / double(RAND_MAX) + (double)(rand() % (EdgeLengthMax - EdgeLengthMin) + EdgeLengthMin + 1);Edge newedge(node1,node2,len);newedge.print();graph.AddEdge(node1, node2, len);graph.AddEdge(node2, node1, len);}          if (NodeCounts % 2 == 1)//奇数,最后一个小组为三个节点{arr_id[NodeCounts-2] = id;arr_id[NodeCounts-1] = id;//添加相应边node1 = arr[NodeCounts - 2] - 1;node2 = arr[NodeCounts - 1] - 1;len = rand() / double(RAND_MAX) + (double)(rand() % (EdgeLengthMax - EdgeLengthMin) + EdgeLengthMin + 1);Edge newedge(node1, node2, len);newedge.print();graph.AddEdge(node1, node2, len);graph.AddEdge(node2, node1, len);}for (int i = 0; i <= NodeCounts - 1; i++)cout << arr[i]-1 << "    ";cout << endl;for (int i = 0; i <= NodeCounts - 1; i++)cout << arr_id[i] << "    " ;cout << endl;//1.3 根据现有的小组随机连接,直到只有一个小组while (id != 1){//任意选择两个存在的小组//首先任意获得第一个被挑选出来的小组group1的编号arr_idint get_random= rand() % NodeCounts;int group1 = 1;int group2 = 1;              group1 = arr_id[get_random];//其次获取在arr_id数组中与grroup1相邻的第二个小组group2的编号for (int i = get_random; i <= get_random+NodeCounts - 1; i++){if (arr_id[(i%NodeCounts)] != group1){group2 = arr_id[(i%NodeCounts)];break;}                                             }//从两个小组中任意挑出一个节点作为连接节点int group1_counts = 0;int group2_counts = 0;//先获得两个小组的数量for (int i = 0; i <= NodeCounts - 1; i++){if (arr_id[i] == group1)group1_counts++;if (arr_id[i] == group2)group2_counts++;}//随机获取在两个小组中被挑选出的节点的序号int node_choose1 = rand()% group1_counts+1;int node_choose2 = rand()% group2_counts + 1;//获取被挑选出来的节点的node_id   ,更新arr_id            group1_counts = 0;group2_counts = 0;node1 = node2 = -1;//重新复位for (int i = 0; i <= NodeCounts - 1; i++){if (arr_id[i] == group1)group1_counts++;if (arr_id[i] == group2)            group2_counts++;if (group1_counts == node_choose1 && node1==-1)//第一次相等的时候node1 = arr[i] - 1;if (group2_counts == node_choose2 && node2==-1)//第一次相等的时候node2 = arr[i] - 1;}//将两个小组合成一个小组,按照“谁小谁做主”的原则,可以预料到最后小组编号全是1int connect_id = group1 < group2 ? group1 : group2;for (int i = 0; i <= NodeCounts - 1; i++){                                   if (arr_id[i] == group1 || arr_id[i] == group2)arr_id[i] = connect_id;}                        //随机生成边长len = rand() / double(RAND_MAX) + (double)(rand() % (EdgeLengthMax - EdgeLengthMin) + EdgeLengthMin + 1);//获取边,并添加Edge newedge(node1, node2, len);printf("连接 %d 小组和 %d 小组 现有小组数为%d\n", group1, group2,id);newedge.print();graph.AddEdge(node1, node2, len);graph.AddEdge(node2, node1, len);for (int i = 0; i <= NodeCounts - 1; i++)cout << arr_id[i] << "    ";cout << endl;              //小组数减一id--;}

结果示意图:

注:
(1)如何随机挑选出两个小组,即group1和group2?
答:首先生成一个随机数random(在0-N-1之间)作为被挑选出的节点,group1=arr_id[random],然后从random为下标开始遍历arr_id数组(循环遍历),直到第一个arr_id[i]!=group1,则有group2=arr_id[i]。
(2)如何在挑选出的小组中随机挑选连接节点,即node1和node2?
答:首先遍历arr_id数组获得group1和group2的节点数count1和count2,根据count1和count2随机产生id1和id2,意思是挑选出在group1和group2中,按照arr_id序列中排在第id1和id2位的节点,然后遍历arr_id数组得到排在id1和id2的节点下标node_id1和node_id2,最后有node1=arr[id1],node2=arr[id2]。
(3)两个小组的连接操作(小组间的吞并)具体是什么?
答:首先生成两个小组连接节点之间的边,然后按照修改两个小组在arr_id数组的值为group1和group2之间较小的一个,也就是小的“吞并”大的。

程序的思路和伪代码

对于无向图(节点为N,边为M):
首先生成N-1条边连通子图,将保证生成图的连通性,具体方法为:

  1. 将N节点按照两个节点随机分成N/2个小组(N为奇数,最后一个小组为三个节点),分完之后,确定其连接关系(小组内相邻两节点之间生成边);
  2. 在现有的小组中随机挑选出两个小组,并在挑选出的小组中随机挑选一个节点作为连接节点,然后连接(即两小组的连接节点之间生成一条边);
  3. 重复2,直到只有一个小组

其次,增加(M-(N-1))条边

  1. 随机生成一条边;
  2. 判断图中是否已经存在该边;若无,则继续3,否则返回1;
  3. 新增加的边数是否为 (M-(N-1))条,若无,则继续1,否则,算法结束。

伪代码为

1.WHILE(true)
2.Graph g=new Graph(n);
3.Edge edge[m];
4.Init subgraph_couts=n/2 ;
5.Init Subgraph[subgraph_couts]= Create_random_array();
6.WHILE(subgraph_couts !=1)
7.  Random_connect(Subgraph[subgraph_couts]);
8.  edge.addNewEdge_for_connect();
9.  Update subgraph_couts;
10. Update Subgraph[subgraph_couts];
11.FOR(i=1 to (m-n+1))
12.  e=generate_random_edge();
13.    IF G is not exist e
14.      edge.addEdge(e);
15.g.addEdge(edge[m]);
16.return g

对于有向图(节点为N,边为M)(这里没有保证有向图的连通性,即生成的有向图并不一定是强连通图或单向连通图):
直接增加(M)条边

  1. 随机生成一条边;
  2. 判断图中是否已经存在该边;若无,则继续3,否则返回1;
  3. 新增加的边数是否为 (M)条,若无,则继续1,否则,算法结束。
    伪代码为
1.WHILE(true)
2.Graph g=new Graph(n);
4.FOR(i=1 to m)
5.  edge=generate_random_edge();
6.    IF edge is not exist
7.      g.addEdge(edge);
8.return g

结果示意图:

主函数代码

详细代码我已经上传至码云:create_random_graph(基于VS2017)

#include <iostream>
#include "Graph.h"
#include <time.h>
#include <iomanip>
using namespace std;
// 程序的主函数
int main()
{//GraphType图的类型 1-无向连通图 2-有向图(随机) //NodeCounts节点个数 EdgeCounts边的个数//有向图中 EdgeCounts在[1,(NodeCounts -1)*NodeCounts ]之间 无向连通图中 EdgeCounts在[NodeCounts -1, (NodeCounts - 1)*NodeCounts / 2]int GraphType = 1, NodeCounts, EdgeCounts; int EdgeLengthMax , EdgeLengthMin ;int edge_max, edge_min;cout << "====本程序自动生成图——矩阵形式====" << endl;while (true){cout << "请输入图的类型(1-无向连通图 2-有向图(随机) ):";cin >> GraphType;//cout << endl;if (GraphType == 1) break;      else if (GraphType == 2) break;else { cout << "输入类型错误,请重新输入!" << endl;}}cout << "请输入节点数:";cin >> NodeCounts;//cout << endl;if (GraphType == 1) {edge_min = NodeCounts - 1;edge_max = (NodeCounts - 1)*NodeCounts / 2;}else {edge_min = 1;edge_max = (NodeCounts - 1)*NodeCounts;}while (true){cout << "请输入边数:" << "(在" << edge_min << "到" << edge_max << "之间)" ;cin >> EdgeCounts;//cout << endl;if (!(EdgeCounts >= edge_min && EdgeCounts <= edge_max)){cout << "输入边数错误,请重新输入!" << endl;}else break;}cout << "请输入边的长度范围(整数且小于999)" << endl;while (true){cout << "最大值:";cin >> EdgeLengthMax;//cout << endl;cout << "最小值:";//cout << endl;cin >> EdgeLengthMin;if (EdgeLengthMin < EdgeLengthMax)break;else cout << "最小不比最大小,请重新输入!"<<endl;}cout << "输入结束,您生成的图信息为:" << endl;if (GraphType == 1) cout << "无向连通图  "; else cout << "随机有向图  ";cout << "节点为" << NodeCounts << "个  "; cout << "边数为" << EdgeCounts;cout << "  边的权值从" << EdgeLengthMin << "到" << EdgeLengthMax << "之间" << endl;//正式计算Graph graph(NodeCounts, EdgeCounts);Edge *edge_sub = new Edge[EdgeCounts];//边数组,用来存储边int edge_counts = 0;if (GraphType == 1)//无向连通图{//step1 //生成一个连通子图,N-1条边//1.1首先随机分组//一个记录节点小组下标的数组int  *arr_id = new int[NodeCounts];for (int i = 0; i < NodeCounts; i++)arr_id[i] = 0;//小组idint id = 0;//产生一个随机节点序列int *arr = new int[NodeCounts];for (int i = 0; i < NodeCounts; i++)arr[i] = 0;int count = 0;srand(time(NULL));while (count < NodeCounts){int val = rand() % NodeCounts;if (!arr[val]){//printf("%d ", val);arr[val] = count + 1;++count;}}/*for (int i = 0; i < NodeCounts; i++)printf("%d ", arr[i]);*///1.2根据随机序列arr,两个节点一组进行分组int node1 = 1, node2 = 1;double len = 0.0;for (int i = 0; i <= NodeCounts - 2; i=i+2){//分组,标记分组号id++;arr_id[i] = id;arr_id[i+1] = id;               //添加相应边node1 = arr[i] - 1;node2 = arr[i + 1] - 1;len = rand() / double(RAND_MAX) + (double)(rand() % (EdgeLengthMax - EdgeLengthMin) + EdgeLengthMin + 1);Edge newedge(node1,node2,len);newedge.print();graph.AddEdge(node1, node2, len);graph.AddEdge(node2, node1, len);}if (NodeCounts % 2 == 1)//奇数,最后一个小组为三个节点{arr_id[NodeCounts-2] = id;arr_id[NodeCounts-1] = id;//添加相应边node1 = arr[NodeCounts - 2] - 1;node2 = arr[NodeCounts - 1] - 1;len = rand() / double(RAND_MAX) + (double)(rand() % (EdgeLengthMax - EdgeLengthMin) + EdgeLengthMin + 1);Edge newedge(node1, node2, len);newedge.print();graph.AddEdge(node1, node2, len);graph.AddEdge(node2, node1, len);}for (int i = 0; i <= NodeCounts - 1; i++)cout << arr[i]-1 << "    ";cout << endl;for (int i = 0; i <= NodeCounts - 1; i++)cout << arr_id[i] << "    " ;cout << endl;//1.3 根据现有的小组随机连接,直到只有一个小组while (id != 1){//任意选择两个存在的小组//首先任意获得第一个被挑选出来的小组group1的编号arr_idint get_random= rand() % NodeCounts;int group1 = 1;int group2 = 1;                group1 = arr_id[get_random];//其次获取在arr_id数组中与grroup1相邻的第二个小组group2的编号for (int i = get_random; i <= get_random+NodeCounts - 1; i++){if (arr_id[(i%NodeCounts)] != group1){group2 = arr_id[(i%NodeCounts)];break;}                                             }//从两个小组中任意挑出一个节点作为连接节点int group1_counts = 0;int group2_counts = 0;//先获得两个小组的数量for (int i = 0; i <= NodeCounts - 1; i++){if (arr_id[i] == group1)group1_counts++;if (arr_id[i] == group2)group2_counts++;}//随机获取在两个小组中被挑选出的节点的序号int node_choose1 = rand()% group1_counts+1;int node_choose2 = rand()% group2_counts + 1;//获取被挑选出来的节点的node_id   ,更新arr_id            group1_counts = 0;group2_counts = 0;node1 = node2 = -1;//重新复位for (int i = 0; i <= NodeCounts - 1; i++){if (arr_id[i] == group1)group1_counts++;if (arr_id[i] == group2)            group2_counts++;if (group1_counts == node_choose1 && node1==-1)//第一次相等的时候node1 = arr[i] - 1;if (group2_counts == node_choose2 && node2==-1)//第一次相等的时候node2 = arr[i] - 1;}//将两个小组合成一个小组,按照“谁小谁做主”的原则,可以预料到最后小组编号全是1int connect_id = group1 < group2 ? group1 : group2;for (int i = 0; i <= NodeCounts - 1; i++){                                   if (arr_id[i] == group1 || arr_id[i] == group2)arr_id[i] = connect_id;}            //随机生成边长len = rand() / double(RAND_MAX) + (double)(rand() % (EdgeLengthMax - EdgeLengthMin) + EdgeLengthMin + 1);//获取边,并添加Edge newedge(node1, node2, len);printf("连接 %d 小组和 %d 小组 现有小组数为%d\n", group1, group2,id);newedge.print();graph.AddEdge(node1, node2, len);graph.AddEdge(node2, node1, len);for (int i = 0; i <= NodeCounts - 1; i++)cout << arr_id[i] << "    ";cout << endl;              //小组数减一id--;}////step2 cout << "继续添加!" << endl;int OthertEdgeCount = EdgeCounts - NodeCounts + 1;while (OthertEdgeCount != 0){node1 = node2 = 1;while (node1 == node2){node1 = rand() % NodeCounts;node2 = rand() % NodeCounts;}if (!graph.IsExistEdge(node1, node2))             {len = rand() / double(RAND_MAX) + (double)(rand() % (EdgeLengthMax - EdgeLengthMin) + EdgeLengthMin + 1);Edge newedge(node1, node2, len);              newedge.print();graph.AddEdge(node1, node2, len);graph.AddEdge(node2, node1, len);                          OthertEdgeCount--;}}                        }if (GraphType == 2)//随机有向图{int node1 = 1, node2 = 1;double len = 0.0;int OthertEdgeCount = EdgeCounts;while (OthertEdgeCount != 0){node1 = node2 = 1;while (node1 == node2){node1 = rand() % NodeCounts;node2 = rand() % NodeCounts;}if (!graph.IsExistEdge(node1, node2)){len = rand() / double(RAND_MAX) + (double)(rand() % (EdgeLengthMax - EdgeLengthMin) + EdgeLengthMin + 1);Edge newedge(node1, node2, len);newedge.print();graph.AddEdge(node1, node2, len);                                 OthertEdgeCount--;}}}   //输出图矩阵graph.print();   return 0;
}

程序运行结果展示

本代码生成无向图为无向连通图,有向图为随机有向图。
生成无向连通图:

  1. 输入:类型、节点个数、边数、边的权值范围;
  2. 生成最小连通子图;

  3. 添加剩余的边,显示生成的图矩阵。

    生成随机有向图:
    输入:类型、节点个数、边数、边的权值范围:
    添加边:
    显示生成的图矩阵:

按要求自动生成无向/有向图(基于C++实现)相关推荐

  1. 自动生成Mapper文件(基于Mybatis Maven插件)

    自动生成Mybatis的Mapper文件 工作中使用mybatis时我们需要根据数据表字段创建pojo类.mapper文件以及dao类,并且需要配置它们之间的依赖关系,这样的工作很琐碎和重复,myba ...

  2. 怎么证明未显式定义构造方法时,编译器会自动生成无参的构造方法?

    在和类和对象篇提到: 当没有显式定义构造方法,编译器会自动提供一个没有参数的构造方法 若类中显式定义了构造方法,则默认的无参构造不再产生 本篇博客就带大家一起来验证~ 首先,显式定义构造方法:即 自己 ...

  3. matlab自动生成报告,一种基于MATLAB的Word报告自动生成方法

    总第 182期 一 种基于MATLAB的Word报告自动生成方法 孙 剑 (信阳农林学院,河南 信阳 464000) 摘要:自动生成Word文档报告功能是办公 自动化系统中的重要组成部分.为高效的完成 ...

  4. Matlab/Simulink自动生成STM32代码_基于模型的开发_环境搭建

    目录 前言 官方简介 Matlab R2018b安装 STM32-MAT/TARGET 安装 STM32CubeMX 安装 STM32CubeIDE, Keil安装 ST-Link驱动安装 微信公众号 ...

  5. lisp自动生成界址点表_基于AutoCAD VBA增减挂钩报备坐标文件自动生成.doc

    基于AutoCAD VBA增减挂钩报备坐标文件自动生成 基于AutoCAD VBA增减挂钩报备坐标文件自动生成 摘要:生成增减挂钩报备坐标文件是一项非常繁琐的工作,会占用大量工作时间.如果利用VBA对 ...

  6. lisp自动生成界址点表_基于AUTO CAD绘制宗地界址点成果表程序的研发

    基于 AUTO CAD 绘制宗地界址点成果表程序的研发 陈亚明 ; 杨俊杰 ; 张胜利 [期刊名称] <科技创新与生产力> [年 ( 卷 ), 期] 2007(161)006 [摘要] 针 ...

  7. java自动生成代码框架_DodoFramework- 一个基于代码生成引擎的Java Web系统自动化开发框架...

    @DodoShowColumn(sortSeq = 0) @DodoField(name = "产品名称", sortSeq = 0, isRemoteCheck = true, ...

  8. 基于GPT2_Chinese文本自动生成

    基于 GPT2-Chinese 模型的中文文本生成项目,可用于中文生成任务. 当下市面上很多文本自动生成业务都是基于该模型二次开发的,可以很少有那种特定垂直领域的模型用于该领域的创作,也就导致大家在使 ...

  9. Makefile之自动生成依赖(8)

    Makefile自动生成头文件依赖是很常用的功能,本文的目的是想尽量详细说明其中的原理和过程. Makefile模板 首先给出一个本人在小项目中常用的Makefile模板,支持自动生成头文件依赖. C ...

最新文章

  1. 阿尔法特磁悬浮制冷机组荣获“2016年度中国数据中心优秀节能产品”殊荣
  2. 如何优雅地使用pdpipe与Pandas构建管道?
  3. K - Anton and Lines CodeForces - 593B
  4. 3-4 第三天 Generator生成器
  5. 拦截器 java_在Java后端如何添加拦截器
  6. NET Core微服务之路:实战SkyWalking+Exceptionless体验生产下追踪系统
  7. Openjudge-计算概论(A)-放苹果
  8. 面试官系统精讲Java源码及大厂真题 - 07 List 源码会问哪些面试题
  9. 大数据分析必须要会的python函数操作!!!
  10. 20.QT中插件编程
  11. 对象的List成员添加元素
  12. linux 系统启动级别,LINUX系统启动级别介绍与解释
  13. 华三服务器管理口地址_不同型号服务器的默认管理IP及账号密码汇总
  14. 继电保护原理3-输电线纵差
  15. 熟悉scrapy的基本使用(创建与运行,目录结构)---爬虫项目
  16. python中Blowfish加密解密
  17. vue导出excel乱码(锟斤拷唷?锟?;锟斤拷)
  18. php储存网页内容的简单示范
  19. java-php-python-ssm医用物品管理系统计算机毕业设计
  20. 刷脸支付上线,追赶二维码支付指日可待?

热门文章

  1. django模型类中,为什不是user_id而是user?
  2. Python开发【第二章】python入门
  3. uni-app -- 改变页面背景颜色
  4. 众里寻他千百度【再谈搜索】
  5. 微信小程序:九宫格抽奖
  6. dbca静默建库踩坑
  7. 图片转world文档 Excel excel 新
  8. OpenCV基础学习
  9. 【英雄九日集训】(七月第一轮)第一天——数组
  10. 免费OFD文件在线转PDF