# APCS實作題2021年1月第2題:流量 > 日期:2023年9月15日 > 作者:王一哲 > 題目來源:110年1月實作題第2題 > [ZeroJudge 題目連結](https://zerojudge.tw/ShowProblem?problemid=f606) <br /> ## 題目 ### 問題描述 有 $n$ 個伺服器編號 $0$ 到 $n-1$,以及 $m$ 個城市編號 $0$ 到 $m-1$,已知第 $i$ 個伺服器要傳送到城市 $j$ 的流量為 $Q[i][j]$。 工程師們在規劃每個伺服器應該要放在哪個城市,對於一個方案 $c = (c_1, c_2, c_3, \dots, c_n)$,表示編號 $i$ 的伺服器要放在城市 $c_i$。 城市之間資料傳輸是需要費用的,若城市 $u$ 要傳送 $f$ 的流量到城市 $v$,費用的計算方式如下: - 若 $u = v$,每單位流量需要花1塊錢。 - 若 $n \neq v$,小於等於1000的流量每單位要3塊錢,大於1000的部份每單位2塊錢。 若城市 $u$ 有多個伺服器都要傳送流量到城市 $v$,會先將這些起點終點相同的傳輸流量相加再計算花費。 工程師們總共提出了 $k$ 種方案,請你找到花費最少的方案所需的費用。 <br /> ### 輸入說明 第一行包含三個整數 $n, m, k$。 接下來 $n$ 行每行有 $m$ 個整數,第 $i$ 行的第 $j$ 個數字為 $Q[i][j]$。 接下來有 $k$ 行,每行有 $n$ 個整數,表示一個方案。 配分 - 20分:$n = 1, k = 1, 1 \leq m \leq 50$ - 30分:$n = 1, 1 \leq m, k \leq 50$ - 50分:$1 \leq n, m, k \leq 50$ <br /> ### 輸出說明 輸出費用最小的方案所需的花費。 <br /> ### 範例一:輸入 ``` 2 3 3 30 23 23 5 25 3 0 0 0 1 0 2 ``` ### 範例一:正確輸出 ``` 217 ``` <br /> ### 範例二:輸入 ``` 3 4 5 500 400 800 200 500 400 100 600 450 420 800 790 0 0 0 0 1 2 0 2 2 2 1 2 1 1 1 ``` ### 範例二:正確輸出 ``` 13470 ``` <br /> ## Python 程式碼 於 ZeroJudge 測試結果,最長運算時間約為 0.1 s,使用記憶體最多約為 3.4 MB,通過測試。 ```python= n, m, k = map(int, input().split()) # 讀取n, m, k Q = [] # 儲存傳輸量資料的串列 for _ in range(n): # 讀取n行傳輸量資料 Q.append(list(map(int, input().split()))) fees = [0]*k # 各種方案的費用 for x in range(k): # 讀取k行的方案 servers = list(map(int, input().split())) # 各個伺服器位在的城市編號 cross = [[0]*m for _ in range(m)] # 跨城市傳輸的流量 for i in range(n): # 讀取 Q[i][j] for j in range(m): if servers[i] == j: # 若伺服器與目標在同一座城市 fees[x] += Q[i][j] # 費用加上流量 else: # 若伺服器與目標在不同城市 cross[servers[i]][j] += Q[i][j] for i in range(m): # 讀取跨城市傳輸的流量 for j in range(m): if cross[i][j] <= 1000: # 流量小於等於1000的算法 fees[x] += cross[i][j]*3 else: # 流量大於1000的算法 fees[x] += 3000 + (cross[i][j]-1000)*2 print(min(fees)) # 印出答案 ``` <br /><br /> 修改取最小值的方法,計算完一個方案的費用時立刻更新最小值。於 ZeroJudge 測試結果,最長運算時間約為 0.1 s,使用記憶體最多約為 3.4 MB,通過測試。 ```python= import sys n, m, k = map(int, input().split()) # 讀取n, m, k Q = [] # 儲存傳輸量資料的串列 for _ in range(n): # 讀取n行傳輸量資料 Q.append(list(map(int, input().split()))) ans = sys.maxsize # 最低費用,預設為最大值 for x in range(k): # 讀取k行的方案 servers = list(map(int, input().split())) # 各個伺服器位在的城市編號 cross = [[0]*m for _ in range(m)] # 跨城市傳輸的流量 fee = 0 # 此方案的費用 for i in range(n): # 讀取 Q[i][j] for j in range(m): if servers[i] == j: # 若伺服器與目標在同一座城市 fee += Q[i][j] # 費用加上流量 else: # 若伺服器與目標在不同城市 cross[servers[i]][j] += Q[i][j] for i in range(m): # 讀取跨城市傳輸的流量 for j in range(m): if cross[i][j] <= 1000: # 流量小於等於1000的算法 fee += cross[i][j]*3 else: # 流量大於1000的算法 fee += 3000 + (cross[i][j]-1000)*2 # 若此方案費用更低則更新答案 ans = min(fee, ans) # 印出答案 print(ans) ``` <br /><br /> ## C++ 程式碼 於 ZeroJudge 測試結果,最長運算時間約為 3 ms,使用記憶體最多約為 340 kB,通過測試。 ```cpp= #include <iostream> #include <climits> #include <algorithm> using namespace std; int main() { int n, m, k; cin >> n >> m >> k; // 讀取n, m, k int Q[n][m]; // 儲存傳輸量資料的陣列 for(int i=0; i<n; i++) { // 讀取n行傳輸量資料 for(int j=0; j<m; j++) { cin >> Q[i][j]; } } int ans = INT_MAX; // 最低費用,預設為最大值 for(int x=0; x<k; x++) { // 讀取k行的方案 // 各個伺服器位在的城市編號 int servers[n]; for(int y=0; y<n; y++) { cin >> servers[y]; } // 跨城市傳輸的流量 int cross[m][m]; for(int y=0; y<m; y++) { for(int z=0; z<m; z++) { cross[y][z] = 0; } } int fee = 0; // 此方案的費用 for(int i=0; i<n; i++) { // 讀取 Q[i][j] for(int j=0; j<m; j++) { if (servers[i] == j) { // 若伺服器與目標在同一座城市 fee += Q[i][j]; // 費用加上流量 } else { // 若伺服器與目標在不同城市 cross[servers[i]][j] += Q[i][j]; } } } for(int i=0; i<m; i++) { // 讀取跨城市傳輸的流量 for(int j=0; j<m; j++) { if (cross[i][j] <= 1000) { // 流量小於等於1000的算法 fee += cross[i][j]*3; } else { // 流量大於1000的算法 fee += 3000 + (cross[i][j]-1000)*2; } } } // 若此方案費用更低則更新答案 ans = min(fee, ans); } cout << ans << endl; // 印出答案 return 0; } ``` <br /><br /> --- ###### tags:`APCS`、`Python`、`C++`