編號為1…N 的N個城市之間以單向路連接,每一條道路有兩個參數:路的長度和通過這條路需付的費用。
Bob和Alice生活在城市1,但是當Bob發現了Alice玩撲克時欺騙他之後,他決定與她翻臉,離開城市1前往城市N。Bob想盡快到達城市N,但是他的錢不多。
希望你幫助Bob找到一條從城市1到城市N的總費用不超過Bob的承受能力的最短路徑。
Input輸入的第一行是3個整數 K, N, R ,其中:
K:表示Bob能承受的最大費用,0 ≤ K ≤ 10000
N:表示城市的總數,2 ≤ N ≤ 100
R:表示道路的條數,1 ≤ R ≤ 10000
接下來的R行,每行用S D L T(以空格隔開)表示一條道路:
S:表示道路的出發城市,1 ≤ S ≤ N
D:表示道路的目標城市,1 ≤ D ≤ N
L:表示道路的長度,1 ≤ L ≤ 100
T:表示通過這條道路需付的費用,0 ≤ T ≤ 100
Output為每個測試用例輸出一行結果:總費用小於或等於最大費用K的最短路徑的長度。如果這樣的路徑不存在,則僅僅輸出 -1 。
Sample Input5 6 7
1 2 2 3
2 4 3 3
3 4 2 4
1 3 4 1
4 6 2 1
3 5 2 0
5 4 3 2
11
Hint測試數據的圖中可能有重邊、有自環。
這題有一定難度,但學完DFS和BFS就要能夠AC它。它是一道典型的搜索題,而且需要強剪枝(去掉 當前已知無效的搜索路徑),以便加快搜索速度。
一看題目,發現很像PTA裡的一道題目:<a href = "https://pta.patest.cn/pta/test/558/exam/4/question/9931">旅游規劃</a>,但是解決思路不同,旅游規劃那道題是用迪傑斯特拉算法的變形,這道題的思路是搜索所有城市1到城市N的可能路徑,然後選一條費用不超過K的最短路徑,有則輸出最短路徑長度,沒有則輸出-1。 偽代碼: 1 DFS(LGraph G, int i, int K)
2 {
3 if(i == N)//說明搜索到了N城市
4 bestDist = currDist; //最短路徑=當前路徑
5 else
6 {
7 循環每一個G中下標為i的頂點的鄰接點
8 if(visited[adjvertex] == false && ck+adjvertex.cost<= K
9 && currDist+adjvertex.dist<bestDist)
10 { /*如果鄰接點沒有被訪問,剪枝:當前費用ck+到鄰接點費用小於等於K,當前距離+到鄰接點的距離小於最短距離*/
11 ck+=adjvertex.cost;
12 currDist+=adjvertex.dist;
13 DFS(G, adjvertex, K);
14 ck-=adjvertex.cost;
15 currDist-=adjvertex.dist;
16
17 }
18 }
19
20 return bestDist;
21 }
1 //DFS 函數自己實現才有收獲
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <stdbool.h>
5 #include <string.h>
6
7 #define MaxVertexNum 101 /* 最大頂點數設為101 */
8 typedef int Vertex; /* 用頂點下標表示頂點,為整型 */
9 typedef struct{ /* 邊的權值設為距離和花費 */
10 int dist, cost;
11 }WeightType;
12
13 /* 邊的定義 */
14 typedef struct ENode *PtrToENode;
15 struct ENode{
16 Vertex V1, V2; /* 有向邊<V1, V2> */
17 WeightType Weight; /* 權重 */
18 };
19 typedef PtrToENode Edge;
20
21 /* 鄰接點的定義 */
22 typedef struct AdjVNode *PtrToAdjVNode;
23 struct AdjVNode{
24 Vertex AdjV; /* 鄰接點下標 */
25 WeightType Weight; /* 邊權重 */
26 PtrToAdjVNode Next; /* 指向下一個鄰接點的指針 */
27 };
28
29 /* 頂點表頭結點的定義 */
30 typedef struct Vnode{
31 PtrToAdjVNode FirstEdge;/* 邊表頭指針 */
32 } AdjList[MaxVertexNum]; /* AdjList是鄰接表類型 */
33
34 /* 圖結點的定義 */
35 typedef struct GNode *PtrToGNode;
36 struct GNode{
37 int Nv; /* 頂點數 */
38 int Ne; /* 邊數 */
39 AdjList G; /* 鄰接表 */
40 };
41 typedef PtrToGNode LGraph; /* 以鄰接表方式存儲的圖類型 */
42
43 LGraph BuildGraph();
44 LGraph CreateGraph( int VertexNum );
45 void InsertEdge( LGraph Graph, Edge E );
46 int DFS(LGraph G, int n);
47
48 bool visited[MaxVertexNum];
49 int K;
50 int ck; //當前花費
51 int bestDist; //最好的路程
52 int currDist; //當前的路程
53
54 int main()
55 {
56 int result;
57 scanf("%d",&K);
58 LGraph G = BuildGraph();
59 memset(visited, false, sizeof(visited));
60 ck = currDist = 0;
61 visited[1] = true;
62 bestDist = 0xffff;
63 result = DFS(G, 1);
64 if (bestDist == 0xffff) //說明沒有符合的路徑,返回-1
65 result = -1;
66 printf("%d\n",result);
67 getchar();getchar();
68 return 0;
69 }
70
71 LGraph CreateGraph( int VertexNum )
72 { /* 初始化一個有VertexNum個頂點但沒有邊的圖 */
73 Vertex V;
74 LGraph Graph;
75
76 Graph = (LGraph)malloc( sizeof(struct GNode) ); /* 建立圖 */
77 Graph->Nv = VertexNum;
78 Graph->Ne = 0;
79 /* 初始化鄰接表頭指針 */
80 /* 注意:這裡默認頂點編號從1開始,到(Graph->Nv) */
81 for (V=1; V<=Graph->Nv; V++)
82 Graph->G[V].FirstEdge = NULL;
83
84 return Graph;
85 }
86
87 void InsertEdge( LGraph Graph, Edge E )
88 {
89 PtrToAdjVNode NewNode;
90
91 /* 插入邊 <V1, V2> */
92 /* 為V2建立新的鄰接點 */
93 NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode));
94 NewNode->AdjV = E->V2;
95 NewNode->Weight = E->Weight;
96 /* 將V2插入V1的表頭 */
97 NewNode->Next = Graph->G[E->V1].FirstEdge;
98 Graph->G[E->V1].FirstEdge = NewNode;
99 }
100
101 LGraph BuildGraph()
102 {
103 LGraph Graph;
104 Edge E;
105 Vertex V;
106 int Nv, i;
107
108 scanf("%d", &Nv); /* 讀入頂點個數 */
109 Graph = CreateGraph(Nv); /* 初始化有Nv個頂點但沒有邊的圖 */
110
111 scanf("%d", &(Graph->Ne)); /* 讀入邊數 */
112 if ( Graph->Ne != 0 ) { /* 如果有邊 */
113 E = (Edge)malloc( sizeof(struct ENode) ); /* 建立邊結點 */
114 /* 讀入邊,格式為"起點 終點 權重",插入鄰接表 */
115 for (i=0; i<Graph->Ne; i++) {
116 scanf("%d %d %d %d", &E->V1, &E->V2, &E->Weight.dist, &E->Weight.cost);
117 InsertEdge( Graph, E );
118 }
119 }
120 return Graph;
121 }