有向圖無向圖領接表深度優先廣度優先最小生成樹
#include <stdio.h> #include <stdlib.h> #include <math.h> #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 #define MAXVEX 100 #define MAXEDGE 100 #define INFINITY 65535 #define MAXSIZE 100 typedef int Status; /* Status是函式的型別 */ typedef int VertexType; /* 頂點型別 */ typedef int EdgeType; /* 邊上的權值型別 */ typedef int Boolean; Boolean visited[MAXVEX]; typedef struct { VertexType vexs[MAXVEX]; /* 頂點表 */ EdgeType arc[MAXVEX][MAXVEX]; /* 鄰接矩陣,看作邊表 */ int numNodes, numEdges; /* 圖中當前的頂點數和邊數 */ }MGraph; typedef struct EdgeNode /* 邊表結點 */ { int adjvex; /* 鄰接點域,儲存該頂點對應的下標 */ int weight; /* 用於儲存權值,對於非網圖可以不需要(手繪圖) */ struct EdgeNode *next; /* 鏈域,指向下一個鄰接點 */ }EdgeNode; typedef struct VertexNode /* 頂點表結點 */ { int in; /* 頂點入度 */ int data; /* 頂點域,儲存頂點資訊 */ EdgeNode *firstedge;/* 邊表頭指標 */ }VertexNode, AdjList[MAXVEX]; typedef struct { AdjList adjList; int numNodes, numEdges; /* 圖中當前頂點數和邊數 */ }graphAdjList,*GraphAdjList; typedef struct /*對邊集陣列Edge結構的定義*/ { int begin; int end; int weight; }Edge; typedef struct { int data[MAXSIZE]; int front; /* 頭指標 */ int rear; /* 尾指標 */ }Queue; Status InitQueue(Queue *Q) /* 初始化空佇列Q */ { Q->front=0; Q->rear=0; return OK; } Status QueueEmpty(Queue Q) /*判斷佇列是否為空*/ { if(Q.front==Q.rear) /* 佇列空的標誌 */ return TRUE; else return FALSE; } Status EnQueue(Queue *Q,int e) /*佇列插入操作*/ { if ((Q->rear+1)%MAXSIZE == Q->front) /* 佇列滿的判斷 */ return ERROR; Q->data[Q->rear]=e; /* 將元素e賦給隊尾 */ Q->rear=(Q->rear+1)%MAXSIZE; /* rear指標向後移一位置, */ /* 若到最後則轉到陣列頭部 */ return OK; } Status DeQueue(Queue *Q,int *e) /*佇列刪除操作*/ { if (Q->front == Q->rear) /* 佇列空的判斷 */ return ERROR; *e=Q->data[Q->front]; /* 將隊頭元素賦值給e */ Q->front=(Q->front+1)%MAXSIZE; /* front指標向後移一位置, */ /* 若到最後則轉到陣列頭部 */ return OK; } Status CreateMGraph(MGraph *G) /* 無向網圖鄰接矩陣表示 */ { int i,j,k,w; //char v[1000]; printf("輸入頂點數和邊數:\n"); scanf("%d%d",&G->numNodes,&G->numEdges); /* 輸入頂點數和邊數 */ for(i=0;i<G->numNodes;i++) //scanf(&G->vexs[i]); G->vexs[i]=i; /* 建立頂點表 */ for(i=0;i<G->numNodes;i++) for(j=0;j<G->numNodes;j++) { if(i==j) G->arc[i][j]=0; else G->arc[i][j]=INFINITY; } printf("對於非網圖另權為1\n"); /* 鄰接矩陣初始化 */ for(k=0;k<G->numEdges;k++) /* 建立鄰接矩陣 */ { printf("輸入第%d條邊(vi,vj)上的下標i,下標j和權w:\n",k+1); scanf("%d%d%d",&i,&j,&w); G->arc[i][j]=w; G->arc[j][i]= G->arc[i][j]; /* 無向圖,矩陣對稱 */ } PrintGraph(G); return OK; } Status CreateDGraph(MGraph *G) /* 有向網圖鄰接矩陣表示 */ { int v1,v2,i,j,k,w; //char ch; printf("圖頂點數和弧數:"); /*確定圖頂點數和邊數*/ scanf("%d%d",&G->numNodes,&G->numEdges); //ch=getchar(); for(i=0;i<G->numNodes;i++) /*定義頂點名稱*/ { printf("第%d個頂點:v",i+1); scanf("%d",&G->vexs[i]); //ch=getchar(); } for(i=0;i<G->numNodes;i++) /*初始化鄰接矩陣*/ for(j=0;j<G->numNodes;j++) { if(i==j) G->arc[i][j]=0; else G->arc[i][j]=INFINITY; } for(k=1;k<=G->numEdges;k++) /*帶方向鄰接矩陣構建*/ { printf("輸入第%d條邊兩個頂點,第一個為弧尾,第二個為弧頭和權值w:\n",k); printf("v"); scanf("%d",&v1); printf("v"); scanf("%d",&v2); printf("權值w:"); scanf("%d",&w); i=LocateVex(G,v1); j=LocateVex(G,v2); //printf("%d %d",i,j); G->arc[i][j]=w; /*賦權*/ } PrintGraph(G); /*打印出有向圖的鄰接矩陣*/ return OK; } void CreateALGraph(MGraph G,GraphAdjList *G1) { int i,j; EdgeNode *e; *G1 = (GraphAdjList)malloc(sizeof(graphAdjList)); (*G1)->numNodes=G.numNodes; (*G1)->numEdges=G.numEdges; for(i= 0;i <G.numNodes;i++) /* 讀入頂點資訊,建立頂點表 */ { (*G1)->adjList[i].in=0; (*G1)->adjList[i].data=G.vexs[i]; (*G1)->adjList[i].firstedge=NULL; /* 將邊表置為空表 */ } for(i=0;i<G.numNodes;i++) /* 建立邊表 */ { for(j=0;j<G.numNodes;j++) { if (G.arc[i][j]==1) { e=(EdgeNode *)malloc(sizeof(EdgeNode)); e->adjvex=j; /* 鄰接序號為j */ e->next=(*G1)->adjList[i].firstedge; /* 將當前頂點上的指向的結點指標賦值給e */ (*G1)->adjList[i].firstedge=e; /* 將當前頂點的指標指向e */ (*G1)->adjList[j].in++; } } } } void DispGraphAdjList(GraphAdjList *G1) { int i; EdgeNode *p; printf("圖的鄰接表表示如下\n"); printf("%6s%6s%2s%12s\n","編號"," ","頂點","相鄰邊編號"); for(i=0;i<(*G1)->numNodes;i++) { printf("%4d v%d",i,(*G1)->adjList[i].data);// for(p=(*G1)->adjList[i].firstedge;p!=NULL;p=p->next) printf("%6d",p->adjvex); printf("\n"); } } Status DestroyMGraph(MGraph G) /*銷燬表*/ { G.numEdges=NULL; G.numNodes=NULL; return OK; } Status LocateVex(MGraph *G,int v) /*找出任意頂點在頂點集中的編號*/ { int a=0,i; for(i=0;i<G->numNodes;i++) { if(v==G->vexs[i]) { return a; } else a++; } if(v>=G->numNodes) { return FALSE; } } Status PrintGraph(MGraph *G) /*列印圖*/ { int i,j; printf("圖中頂點有%3d個,分別為:",G->numNodes); for(i=0;i<G->numNodes;i++) printf("v%d ",G->vexs[i]); printf("\n鄰接矩陣關係:\n"); for(i=0;i<G->numNodes;i++) { for(j=0;j<G->numNodes;j++) { if(G->arc[i][j]==INFINITY) printf(" ∞"); else printf("%6d",G->arc[i][j]); } printf("\n"); } return OK; } void DFS(MGraph G,int i) /*鄰接矩陣的深度遍歷演算法*/ { int j; visited[i]=TRUE; printf("v%d ",G.vexs[i]); for(j=0;j<G.numNodes;j++) if(G.arc[i][j]==1&&!visited[j]) DFS(G,j); } void DFSTraverse(MGraph G) /*鄰接矩陣的深度優先遞迴演算法*/ { int i; for(i=0;i<G.numNodes;i++) visited[i]=FALSE; for(i=0;i<G.numNodes;i++) if(!visited[i]) DFS(G,i); } void DFS1(GraphAdjList G1,int i) /*鄰接表的深度遍歷演算法*/ { EdgeNode *p; visited[i]=TRUE; printf("v%d ",G1->adjList[i].data); p=G1->adjList[i].firstedge; while(p) { if(!visited[p->adjvex]) DFS1(G1,p->adjvex); p=p->next; } } void DFSTraverse1(GraphAdjList G1) /*鄰接表的深度優先遞迴演算法*/ { int i; for(i=0;i<G1->numNodes;i++) visited[i]=FALSE; for(i=0;i<G1->numNodes;i++) if(!visited[i]) DFS1(G1,i); } void BFSTraverse(MGraph G) /*鄰接矩陣的廣度遍歷演算法*/ { int i, j; Queue Q; /*定義佇列Q*/ for(i=0; i< G.numNodes; i++) visited[i] = FALSE; InitQueue(&Q); /* 初始化佇列 */ for(i = 0; i < G.numNodes; i++) { if (!visited[i]) /* 未訪問過處理 */ { visited[i]=TRUE; /* 設定當前頂點訪問過 */ printf("v%d ", G.vexs[i]); /* 列印頂點*/ EnQueue(&Q,i); /* 頂點入隊 */ while(!QueueEmpty(Q)) /* 若當前佇列不為空 */ { DeQueue(&Q,&i); /* 將隊對元素出佇列,賦值給i */ for(j=0;j<G.numNodes;j++) { if(G.arc[i][j] == 1 && !visited[j]) /* 判斷其它頂點若與當前頂點存在邊且未訪問過 */ { visited[j]=TRUE; /* 將找到的此頂點標記為已訪問 */ printf("v%d ", G.vexs[j]); /* 列印頂點 */ EnQueue(&Q,j); /* 將找到的此頂點入佇列 */ } } } } } } void BFSTraverse1(GraphAdjList G1) /*鄰接表的廣度遍歷演算法*/ { int i; EdgeNode *p; Queue Q; for(i = 0; i < G1->numNodes; i++) visited[i] = FALSE; InitQueue(&Q); for(i = 0; i < G1->numNodes; i++) { if (!visited[i]) { visited[i]=TRUE; printf("v%d ",G1->adjList[i].data);/* 列印頂點 */ EnQueue(&Q,i); while(!QueueEmpty(Q)) { DeQueue(&Q,&i); p = G1->adjList[i].firstedge; /* 找到當前頂點的邊錶鏈表頭指標 */ while(p) { if(!visited[p->adjvex]) /* 若此頂點未被訪問 */ { visited[p->adjvex]=TRUE; printf("v%d ",G1->adjList[p->adjvex].data); EnQueue(&Q,p->adjvex); /* 將此頂點入佇列 */ } p = p->next; /* 指標指向下一個鄰接點 */ } } } } } void MiniSpanTree_Prim(MGraph *G)/* Prim演算法生成最小生成樹 */ { int min, i, j, k; int adjvex[MAXVEX]; /* 儲存相關頂點下標 */ int lowcost[MAXVEX]; /* 儲存相關頂點間邊的權值 */ lowcost[0] = 0; /* 初始化第一個權值為0,即v0加入生成樹 */ /* lowcost的值為0,在這裡就是此下標的頂點已經加入生成樹 */ adjvex[0] = 0; /* 初始化第一個頂點下標為0 */ for(i = 1; i < G->numNodes; i++) /* 迴圈除下標為0外的全部頂點 */ { lowcost[i] = G->arc[0][i]; /* 將v0頂點與之有邊的權值存入陣列 */ adjvex[i] = 0; /* 初始化都為v0的下標 */ } for(i = 1; i < G->numNodes; i++) { min = INFINITY; /* 初始化最小權值為∞, */ /* 通常設定為不可能的大數字如32767、65535等 */ j = 1; k = 0; while(j < G->numNodes) /* 迴圈全部頂點 */ { if(lowcost[j]!=0 && lowcost[j] < min)/* 如果權值不為0且權值小於min */ { min = lowcost[j]; /* 則讓當前權值成為最小值 */ k = j; /* 將當前最小值的下標存入k */ } j++; } printf("(%d, %d)\n", adjvex[k], k);/* 列印當前頂點邊中權值最小的邊 */ lowcost[k] = 0; /* 將當前頂點的權值設定為0,表示此頂點已經完成任務 */ for(j = 1; j < G->numNodes; j++) /* 迴圈所有頂點 */ { if(lowcost[j]!=0 && G->arc[k][j] < lowcost[j]) { /* 如果下標為k頂點各邊權值小於此前這些頂點未被加入生成樹權值 */ lowcost[j] = G->arc[k][j];/* 將較小的權值存入lowcost相應位置 */ adjvex[j] = k; /* 將下標為k的頂點存入adjvex */ } } } } void Swapn(Edge *edges,int i, int j)/* 交換權值 以及頭和尾 */ { int temp; temp = edges[i].begin; edges[i].begin = edges[j].begin; edges[j].begin = temp; temp = edges[i].end; edges[i].end = edges[j].end; edges[j].end = temp; temp = edges[i].weight; edges[i].weight = edges[j].weight; edges[j].weight = temp; } void sort(Edge edges[],MGraph *G)/* 對權值進行排序 */ { int i, j; for ( i = 0; i < G->numEdges; i++) { for ( j = i + 1; j < G->numEdges; j++) { if (edges[i].weight > edges[j].weight) { Swapn(edges, i, j); } } } printf("權排序之後的為:\n"); for (i = 0; i < G->numEdges; i++) { printf("(%d, %d) %d\n", edges[i].begin, edges[i].end, edges[i].weight); } } int Find(int *parent, int f)/* 查詢連線頂點的尾部下標 */ { while ( parent[f] > 0) { f = parent[f]; } return f; } void MiniSpanTree_Kruskal(MGraph G)/* 生成最小生成樹 */ { int i, j, n, m; int k = 0; int parent[MAXVEX];/* 定義一陣列用來判斷邊與邊是否形成環路 */ Edge edges[MAXEDGE];/* 定義邊集陣列,edge的結構為begin,end,weight,均為整型 */ for ( i = 0; i < G.numNodes-1; i++)/* 用來構建邊集陣列並排序*/ { for (j = i + 1; j < G.numNodes; j++) { if (G.arc[i][j]<INFINITY) { edges[k].begin = i; edges[k].end = j; edges[k].weight = G.arc[i][j]; k++; } } } sort(edges, &G); for (i = 0; i < G.numNodes; i++) parent[i] = 0; /* 初始化陣列值為0 */ printf("列印最小生成樹:\n"); for (i = 0; i < G.numEdges; i++) /* 迴圈每一條邊 */ { n = Find(parent,edges[i].begin); m = Find(parent,edges[i].end); if (n != m) /* 假如n與m不等,說明此邊沒有與現有的生成樹形成環路 */ { parent[n] = m; /* 將此邊的結尾頂點放入下標為起點的parent中。 */ /* 表示此頂點已經在生成樹集合中 */ printf("(%d, %d) %d\n", edges[i].begin, edges[i].end, edges[i].weight); } } } int main() { int a,u,m,end_loop=0; char value; MGraph G; GraphAdjList G1; printf("*******************************************************************\n"); printf("************-> case 0:結束迴圈退出 ****************\n"); printf("************-> case 1:定義構造圖(鄰接矩陣)無向圖 ****************\n"); printf("************-> case 2:定義構造圖(鄰接矩陣)有向圖 ****************\n"); printf("************-> case 3:定義構造圖(鄰接表) ****************\n"); printf("************-> case 4:銷燬圖 ****************\n"); printf("************-> case 5:查詢頂點集vex[i]中一點的標號 ****************\n"); printf("************-> case 6:輸出當前圖(鄰接矩陣) ****************\n"); printf("************-> case 7:鄰接矩陣的DFS深度優先遍歷 ****************\n"); printf("************-> case 8:鄰接表的DFS深度優先遍歷 ****************\n"); printf("************-> case 9:鄰接矩陣的BFS廣度優先遍歷 ****************\n"); printf("************-> case 10:鄰接表的BFS廣度優先遍歷 ****************\n"); printf("************-> case 11:prim演算法求最小生成樹 ****************\n"); printf("************-> case 12:kruskal演算法求最小生成樹 ****************\n"); printf("************-> case 13:鄰接表建表生成 ****************\n"); printf("*******************************************************************\n"); while(scanf("%d",&a)!=EOF) { switch(a) { case 0:end_loop=1;break; case 1:{ CreateMGraph(&G); printf("************-> case 4:銷燬圖 ****************\n"); printf("************-> case 6:輸出當前圖(鄰接矩陣) ****************\n"); printf("************-> case 7:鄰接矩陣的DFS深度優先遍歷 ****************\n"); printf("************-> case 9:鄰接矩陣的BFS廣度優先遍歷 ****************\n"); printf("************-> case 11:prim演算法求最小生成樹 ****************\n"); printf("************-> case 12:kruskal演算法求最小生成樹 ****************\n"); break; } case 2:CreateDGraph(&G);break; case 3:{ CreateMGraph(&G); /*以鄰接矩陣讀入資料後生成鄰接表*/ CreateALGraph(G,&G1); DispGraphAdjList(&G1); printf("************-> case 4:銷燬圖 ****************\n"); printf("************-> case 8:鄰接表的DFS深度優先遍歷 ****************\n"); printf("************-> case 10:鄰接表的BFS廣度優先遍歷 ****************\n"); printf("************-> case 13:鄰接表建表生成 ****************\n"); break; } case 4:{ DestroyMGraph(G); printf("圖已銷燬!\n"); printf("\n"); break; } case 5:{ printf("輸入要查詢的頂點:v"); scanf("%d",&u); m=LocateVex(&G,u); if(m==-1) printf("出錯!\n"); else printf("查詢頂點的陣列編號為:%d\n",m); break; } case 6:PrintGraph(&G);printf("\n");break; case 7:DFSTraverse(G);printf("\n");break; case 8:DFSTraverse1(G1);printf("\n");break; case 9:BFSTraverse(G);printf("\n");break; case 10:BFSTraverse1(G1);printf("\n");break; case 11:MiniSpanTree_Prim(&G);printf("\n");break; case 12:MiniSpanTree_Kruskal(G);printf("\n");break; case 13:DispGraphAdjList(&G1);printf("\n");break; } if(end_loop==1) break; } return 0; }
相關推薦
有向圖無向圖領接表深度優先廣度優先最小生成樹
#include <stdio.h> #include <stdlib.h> #include <math.h> #define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 #
圖的廣度遍歷、深度遍歷及最小生成樹書演算法(Prim、Kruskal)
typedef struct { char vertex[VertexNum]; //頂點表 int edges[VertexNum][VertexNum];
有向圖 無向圖 尤拉路 尤拉圖
如果圖G中的一個路徑包括每個邊恰好一次,則該路徑稱為尤拉路徑(Euler path)。 ——百度百科 如果一個迴路是尤拉路徑,則稱為歐拉回路(Euler circuit)。 ——百度百科
鄰接表表示圖(有向、無向圖)及廣度、深度遍歷)
鄰接表表示圖 #include <iostream> #include <malloc.h> #include <queue> using namespace std; #define VertexType char #define MaxVerte
圖(有向圖,無向圖)的鄰接矩陣表示C++實現(遍歷,拓撲排序,最短路徑,最小生成樹) Implement of digraph and undigraph using adjacency matrix
本文實現了有向圖,無向圖的鄰接矩陣表示,並且實現了從建立到銷燬圖的各種操作。 以及兩種圖的深度優先遍歷,廣度優先遍歷,Dijkstra最短路徑演算法,Prim最小生成樹演算法,有向圖的拓撲排序演算法。 通過一個全域性變數控制當前圖為有向圖還是無向圖。 若為無向圖,則生成的
基於鄰接表的圖建立(有向圖+無向圖)
圖的表示(建立)有兩種方法: ①鄰接矩陣:A(i,j)=1表示i,j存在一條邊,空間複雜度O(n^2),稠密圖 ②鄰接表:只記錄存在的邊,Vector+List的資料結構,稀疏圖 鄰接矩陣的圖建立這
有向圖 無向圖和建立(陣列表示法)和深度優先訪問
有向圖和無向圖差別就是一句程式碼的差別 ,無向圖中程式碼註釋掉即可 有向圖和有向網的差別也就是權值的差別 有向網需要賦予權值 有向圖有連線自動賦值為1 深度優先採用遞迴方法(參考前面幾篇文章,裡面有具體的深度優先和廣度優先訪問和佇列基本操作) 廣度優先採用佇列 上程
無向帶權圖的最小生成樹算法——Prim及Kruskal算法思路
下一個 必須 循環 算法與數據結構 最小值 邊集 當前 知識 所有 邊賦以權值的圖稱為網或帶權圖,帶權圖的生成樹也是帶權的,生成樹T各邊的權值總和稱為該樹的權。 最小生成樹(MST):權值最小的生成樹。 生成樹和最小生成樹的應用:要連通n個城市需要n-1條邊線路
所有邊權均不相同的無向圖最小生成樹是唯一的證明
eight weight nbsp 不同的 權重 cnblogs 成了 http 方法 設G是所有邊權均不相同的無向聯通圖。 證明一: 首先,易證圖G中權值最小的邊一定是最小生成樹中的邊。(否則最小生成樹加上權值最小的邊後構成一個環,去掉環中任意一條非此邊則形成了另一
1212 無向圖最小生成樹
alt 時間 難度 布爾 too 數組 star tar += 1212 無向圖最小生成樹 基準時間限制:1 秒 空間限制:131072 KB 分值: 0 難度:基礎題 收藏 關註 N個點M條邊的無向連通圖,每條邊有一個權值,求該圖的最小生成樹。 In
[Data Structure & Algrithom] 無向圖的最小生成樹
kruskal算法 如果 data spa amp imu 數據 結點 實現 最小生成樹(Minimum Spanning Tree) - 連接所有頂點的邊的權值之和最小的樹 Prim算法 基本思路 - 設 圖的頂點集合為V;其最小生成樹的頂點集合為U 將某個頂點放入U
51 nod 1212 無向圖最小生成樹(Kruckal演算法/Prime演算法圖解)
1212 無向圖最小生成樹 N個點M條邊的無向連通圖,每條邊有一個權值,求該圖的最小生成樹。 收起 輸入 第1行:2個數N,M中間用空格分隔,N為點的數量,M為邊的數量。(2 <= N <= 1000, 1 <= M <= 50000) 第2 -
51nod 1212 無向圖最小生成樹
數量 color def main tdi ring () return print N個點M條邊的無向連通圖,每條邊有一個權值,求該圖的最小生成樹。 輸入 第1行:2個數N,M中間用空格分隔,N為點的數量,M為邊的數量。(2 <= N &l
(圖論)51NOD 1212 無向圖最小生成樹
N個點M條邊的無向連通圖,每條邊有一個權值,求該圖的最小生成樹。 輸入 第1行:2個數N,M中間用空格分隔,N為點的數量,M為邊的數量。(2 <= N <= 1000, 1 <= M <= 50000) 第2 - M + 1
鏢局運鏢---無向圖的最小生成樹
假設有n個城市和m條道路,對應無向圖中的點和邊。每條路的過路費對應邊的權值。鏢局現在需要選擇一些道路進行疏通,以便邊距可以達到任意一個城鎮,要求花費的銀子越少越好。換句話說,鏢局的要求就是用最少的邊讓圖連通(任意兩點之間可以互相到達),將多餘的邊去掉。 很顯然,要想
51Nod1212 無向圖最小生成樹
#include<iostream> #include<cstring> #include<cstdio> using namespace std; int map[
uva 11183 有向圖的最小生成樹
AC程式碼 #include<bits/stdc++.h> using namespace std; #define N 1300 int pre[N]; int in[N]; int id[N]; int v[N]; struct edge{
有向圖最小生成樹
基礎:無向圖的kruskal演算法 摘抄: 最 小樹形圖,就是給有向帶權圖中指定一個特殊的點root,求一棵以root為根的有向生成樹T,並且T中所有邊的總權值最小。最小樹形圖的第一個演算法是 1965年朱永津和劉振巨集提出的複雜度為O(VE)的演算法。 判斷是否存在樹形圖
51nod 1212 無向圖最小生成樹(Kruskal演算法)
收藏 關注 N個點M條邊的無向連通圖,每條邊有一個權值,求該圖的最小生成樹。 Input 第1行:2個數N,M中間用空格分隔,N為點的數量,M為邊的數量。(2 <= N <= 1000, 1 <= M <= 5
圖:最小生成樹:prim演算法 普里姆演算法 ,(無向圖的實現)
#ifndef _GRAPH_H #define _GRAPH_H #define DEFAULT_VERTEX_SIZE 10 typedef struct { int x; int y; int cost; }edge; template&l