| 試題編號: | 201503-5 |
| 試題名稱: | 最小花費 |
| 時間限制: | 4.0s |
| 內存限制: | 256.0MB |
| 問題描述: | 問題描述 C國共有n個城市。有n-1條雙向道路,每條道路連接兩個城市,任意兩個城市之間能互相到達。小R來到C國旅行,他共規劃了m條旅行的路線,第i條旅行路線的起點是si,終點是ti。在旅行過程中,小R每行走一單位長度的路需要吃一單位的食物。C國的食物只能在各個城市中買到,而且不同城市的食物價格可能不同。 然而,小R不希望在旅行中為了購買較低價的糧食而繞遠路,因此他總會選擇最近的路走。現在,請你計算小R規劃的每條旅行路線的最小花費是多少。輸入格式 第一行包含2個整數n和m。 第二行包含n個整數。第i個整數wi表示城市i的食物價格。 接下來n-1行,每行包括3個整數u, v, e,表示城市u和城市v之間有一條長為e的雙向道路。 接下來m行,每行包含2個整數si和ti,分別表示一條旅行路線的起點和終點。輸出格式 輸出m行,分別代表每一條旅行方案的最小花費。樣例輸入6 41 7 3 2 5 61 2 41 3 52 4 13 5 23 6 12 54 66 45 6樣例輸出35162613樣例說明 對于第一條路線,小R會經過2->1->3->5。其中在城市2處以7的價格購買4單位糧食,到城市1時全部吃完,并用1的價格購買7單位糧食,然后到達終點。評測用例規模與約定 前10%的評測用例滿足:n, m ≤ 20, wi ≤ 20; 前30%的評測用例滿足:n, m ≤ 200; 另有40%的評測用例滿足:一個城市至多與其它兩個城市相連。 所有評測用例都滿足:1 ≤ n, m ≤ 105,1 ≤ wi ≤ 106,1 ≤ e ≤ 10000。 |
問題鏈接:CCF201503試題。
原題鏈接:最小花費。
問題描述:參見上文。
問題分析:這是一個圖的算法問題。n個結點n-1條邊,任意兩個結點都相互聯通,說明是一個樹,即任意兩點之間只有一條唯一的通路。可以用DFS來尋找一個從起點到終點的通路,算出最小花費,但是過于費時間,只得了30分。這個需要從算法上進行徹底的改進!這個解法的問題在于需要求得起點到終點得對<src,dest>多的時候,需要每次都做一次DFS,總體上時間復雜度過高。
程序說明:程序中,圖用鄰接表表示。對于輸入的m對起點和終點,分別用DFS尋找它們之間的路徑,然后算出最小花費。
提交后得30分的C++語言程序如下:
/* CCF201503-5 最小花費 */#include <iostream>#include <cstring>#include <vector>using namespace std;typedef unsigned long long ULL;const int MAXN = 100000;ULL PRice[MAXN+1];int visited[MAXN+1];struct adjacency { int node, edge; adjacency(int n, int e) { node = n; edge = e;}};vector<adjacency> g[MAXN+1];struct node { int node, edge;};int N, M;ULL ans;bool endflag;void dfs(int node, int end, ULL miniprice){ ULL currprice; ULL cost; if(node == end) { cout << ans << endl; endflag = true; return; } else { visited[node] = 1; for(int i=0; i<(int)g[node].size() && !endflag; i++) { if(!visited[g[node][i].node]) { currprice = min(miniprice, price[node]); cost = g[node][i].edge * currprice; ans += cost; dfs(g[node][i].node, end, currprice); ans -= cost; } } }}int main(){ int u, v, e; // 輸入數據 cin >> N >> M; for(int i=1; i<=N; i++) cin >> price[i]; for(int i=1; i<=N-1; i++) { cin >> u >> v >> e; g[u].push_back(adjacency(v, e)); g[v].push_back(adjacency(u, e)); } // 輸入起點和終點,用DFS計算最小花費,并且輸出結果 int start, end; for(int i=0; i<M; i++) { cin >> start >> end; memset(visited, 0, sizeof(visited)); endflag = false; ans = 0; dfs(start, end, price[start]); } return 0;}參考題解(100分):第四屆CCF軟件能力認證 第五題(最小花費)題解。
參考題解(這個解法似乎更加有效):第四屆CCF軟件能力認證(CSP2015) 第五題(最小花費)題解。
新聞熱點
疑難解答