题目描述:
思路:
①真没想到,题目的“可以连一条边”的意思是,就是得连一条边上去,更新原来的图,然后才继续找满足depth=3的结点,而不是只是记录可以连这么一条边就行了。是题目有问题还是我理解能力不行?
②用图的DFS应用到树的DFS,因为树就是特殊的图,也可以用邻接矩阵来表示。
③用深度优先搜索,从一个节点出发,查找离他深度为3的结点,然后连线,并更新图(树)的邻接矩阵。
④然后从连线处再次出发,递归调用DFS,传入depth=1。这是为了找到新加边之后,从这条边走出去有没有新的depth=3的结点。
⑤用countt记录每次找到depth=3的未连接点的数量。
代码:
using namespace std;
#include<iostream>
#include<string>
enum class EC {
OK, Shit
};
#define MaxInt 32767 // 表示极大值,即oo
#define MVNum 100 // 最大顶点数
int* IsVisited;
int countt = 0; //用来看看长度是否到4
class AMGraph {
public:
string vexs[MVNum]; //顶点表
int arcs[MVNum][MVNum]; //邻接矩阵
int vexnum, arcnum; //图的当前点数和边数
};
//————【查找某个值在顶点表的位置
int LocateVex(AMGraph& G, string& u) {
for (int i = 0; i < G.vexnum; i++) {
if (u == G.vexs[i])
return i;
}
return -1;
}
//————【创建无向网
EC CreateUDN(AMGraph& G) {
cin >> G.vexnum;
int nn = G.vexnum;
IsVisited = new int[nn];
//初始化IsVisited为0
for (int i = 0; i < G.vexnum; i++) {
IsVisited[i] = 0;
}
G.arcnum = G.vexnum - 1;
//给顶点赋值
for (int i = 0; i < G.vexnum; i++) {
G.vexs[i] = std::to_string(i + 1);
}
//给边的权赋初始值(无穷大)
for (int i = 0; i < G.vexnum; i++) {
for (int j = 0; j < G.vexnum; j++) {
G.arcs[i][j] = MaxInt;
}
}
//开始给边赋真正的权值
for (int k = 0; k < G.arcnum; k++) {
string v1, v2;
cin >> v1 >> v2;
int m = LocateVex(G, v1);
int n = LocateVex(G, v2);
G.arcs[n][m] = G.arcs[m][n] = 1;
}
return EC::OK;
}
//————【深度优先遍历,这里的v是顶点列表里面的下标(不是第几个顶点)
void DFS(AMGraph& G, int v, int depth, const int start) { //start表示起点
if (depth == 3) {
if (G.arcs[v][start] != 1) { //深度为3的结点和起点之间原先没有连线,才count++,然后连一条边
countt++;
G.arcs[v][start] = G.arcs[start][v] = 1;
DFS(G, v, 1, start);
}
}
IsVisited[v] = 1; //访问第v+1个顶点
for (int w = 0; w < G.vexnum; w++) {
if (G.arcs[v][w] != MaxInt && IsVisited[w] == 0) //如果两点之间存在边,并且另一个点未被访问
{
DFS(G, w, depth + 1, start);
}
}
}
int main() {
AMGraph G;
CreateUDN(G);
for (int i = 0; i < G.vexnum; i++)
{
DFS(G, i, 0, i);
for (int i = 0; i < G.vexnum; i++)
{
IsVisited[i] = 0;
}
}
cout << endl << countt << endl;
}