图中的顶点关系比树的更加复杂,再也不是单纯的层次关系,而是平等的,点与点均可能连通,因此存储就须要模拟一个平面,在图的关系比较稀疏是用邻接表(使用线性存储),反之使用邻接矩阵,二维数据便可表示出一个平面。图的问题,主要是遍历和路径,难点在于找到相应算法(或者多种算法结合),解决一些实际问题时通常都会对算法进行相应的改动。
有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。如今须要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。若是有若干条路径都是最短的,那么须要输出最便宜的一条路径。
输入格式:
输入说明:输入数据的第1行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0~(N−1);M是高速公路的条数;S是出发地的城市编号;D是目的地的城市编号。随后的M行中,每行给出一条高速公路的信息,分别是:城市一、城市二、高速公路长度、收费额,中间用空格分开,数字均为整数且不超过500。输入保证解的存在。
输出格式:
在一行里输出路径的长度和收费总额,数字间以空格分隔,输出结尾不能有多余空格。
输入样例:
4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20
输出样例:
3 40算法
此题就是找最短路径,能够使用Dijkstra,使用一个包括距离和价钱的结构体建图,而后比较时优先考虑距离其次到价格。
结构体:数组
typedef struct { int weight=INF;//距离 int cost=INF;//价格 }VNode;
伪代码:网络
int main() { cin >> N >> M >> S >> D; 输入城市数量,和高速路和出发点、目的地 for (i = 0 to M) { cin >> x >> y >> w >> c; 读入高速路信息 graph[x][y].weight = graph[y][x].weight = w;//距离 graph[x][y].cost = graph[y][x].cost = c;//价格 } 调用Dijkstra(S, D); return 0; }
Dijkstra(S, D);函数app
void Dijkstra(int v,int d) { VNode dist[501];//记录最短路径 int k; int s[501] = { 0 };//S[i]=1表示顶点i在S中,S[i]=0表示顶点i在u中 VNode mindis; for (i = 0 to N)//N个顶点 { dist[i].weight = graph[v][i].weight;//距离初始化 dist[i].cost = graph[v][i].cost;//价格初始化 } s[v] = 1; for (i = 0 to N - 1) { mindis.weight = INF 初始化为最大值 for (j = 0 toj < N) { if (s[j] == 0 && dist[j].weight <= mindis.weight)若是j属于u中(没有被选)而且距离小于等于最小值 { if (dist[j].weight < mindis.weight)距离小于最小值 { k = j; mindis.weight = dist[j].weight; mindis.cost = dist[j].cost; 把该顶点信息记录 } else if(dist[j].cost < mindis.cost)距离相等,比较价格 { k = j; mindis.cost = dist[j].cost; 把该顶点信息记录 } } } s[k] = 1; for (j = 0 to N) { if(j点属于u(没有被选过)) if(若是k和j连通) if (graph[k][j].weight + dist[k].weight < dist[j].weight)若是过k点到j点的新路径比原来短 { dist[j].weight = graph[k][j].weight + dist[k].weight;更新为短路径 dist[j].cost = graph[k][j].cost + dist[k].cost; } else if(graph[k][j].weight + dist[k].weight == dist[j].weight) { if (graph[k][j].cost + dist[k].cost < dist[j].cost)若是过k点到j点的新路径比原来便宜 { dist[j].cost = graph[k][j].cost + dist[k].cost;更新为新价格 } } } } 输出最短路径和价格 }
Q:
看错题目而后误觉得是输出目的地和价格,而后觉得是bug找半天.。。。(还能过一个是最骚的),仔细看题目发现是输出路径的长度和价格函数
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学习
此题要求是修建公路使得任何两个村庄都有路到达而且是最短,对于题中提到村庄之间已经有公路,只需把此类村庄的距离当作0便可。而后经过prim生成最小生成树 注意:为了简单起见此题邻接矩阵的0并不是常规prim算法中表明已经加入U(标记为选过),而是表明距离为0,标记则由visite[i]完成。
int main() { for (i=1 to N) { for (j = 1 to N) { 读入村庄之间的距离到矩阵中 } } for (i = 0 to q) { 读入已经修有路的村庄 graph[a][b] = graph[b][a]=0设置距离为零 } 调用prim函数 输出最小修路长度 return 0; }
prim函数spa
int Prim(int v) { for (i = 1 to N)N个村庄 { 对lowcost和closest数组初始化 lowcost[i] = graph[v][i]距离 closest[i] = v路径 } visite[v] = 1标记已经加入U for (i = 1 to N) { for (j = 1 to N) { 查找lowcost中未加入U(即visite[j]=0)最小的点 用k记录 } 找到后把距离累加到sum中 把该点标记已经加入U for (int j = 1; j <= N; j++) { 修改lowcost和closet if (visite[j]== 0 && graph[k][j] < lowcost[j])若是经过k到未选的点有短的距离 { lowcost[j] = graph[k][j]; closest[j] = k; } } } 返回return sum; }
A:两个wa,是此处以前没有两个置为0(无向图),设计
六度空间”理论又称做“六度分隔(Six Degrees of Separation)”理论。这个理论能够通俗地阐述为:“你和任何一个陌生人之间所间隔的人不会超过六个,也就是说,最多经过五我的你就可以认识任何一个陌生人。”如图1所示。3d
假如给你一个社交网络图,请你对每一个节点计算符合“六度空间”理论的结点占结点总数的百分比。
输入格式:
输入第1行给出两个正整数,分别表示社交网络图的结点数N(1<N≤10
4
,表示人数)、边数M(≤33×N,表示社交关系数)。随后的M行对应M条边,每行给出一对正整数,分别是该条边直接连通的两个结点的编号(节点从1到N编号)。
输出格式:
对每一个结点输出与该结点距离不超过6的结点数占结点总数的百分比,精确到小数点后2位。每一个结节点输出一行,格式为“结点编号:(空格)百分比%”。
输入样例:
10 9
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
输出样例:
1: 70.00%
2: 80.00%
3: 90.00%
4: 100.00%
5: 100.00%
6: 100.00%
7: 100.00%
8: 90.00%
9: 80.00%
10: 70.00%code
此题有点的像树的层次遍历,使用queue辅助搜索,visite[i]标记已经认识过的人,而后经过广度优先搜索,把全部人都认识完或者已经达到第六层(最多经过五我的认识)就能够结束搜索。
图结构体 typedef struct { int **edgs;(直接声明数组会爆) double n, e; }MatGraph;
int main() { 为邻接矩阵分配内存,直接声明会爆 for (i = 0 to M)邻接矩阵初始化 { int x, y; cin >> x >> y; G.edgs[x][y] = G.edgs[y][x] = 1; } for (i = 1 to N)调用N次广搜 { 调用BFS(G, i); } delete内存 return 0; }
void BFS(MatGraph G,int v) { 使用cur表示当前访问的顶点 ,last表示该层次的最后一个顶点 当cur==last声明该层次遍历结束 while (!q.empty()&&level<6)//队空或者层数到6 { 从队列去队头元素 temp =cur= q.front(); for (int i = 1; i <=G.n; i++) { if (G.edgs[temp][i] != 0 && visite[i] == 0)寻找经过当前点能够认识其余点 { visite[i] = 1;标记已认识 q.push(i);入队 sum++;认识人数 } } if (cur == last)//遍历一层结束 { if (!q.empty()) { last = q.back(); level++; } } } printf("%d: %.2f%%\n",v,sum*100 / (G.n));输出结果 }
A:直接过了,注意下层次和标记就能够了,
visite[i]等于1才是标记为已选,可是打错,而后编译器一直提示的是内存爆了,我觉得是数组问题,后来才发现是该处错误引起的无限循环。