今年2018年的杭電計算機學院複試題的第一道題目和第二道題目雖然題目比較長,可是比較簡單和基礎,這裏就不詳細說明了。算法
第三道題目是用到數據結構中的知識。編程
題目以下:數據結構
瓜農王大爺去年種西瓜賺了很多錢。看到收入不錯,今年他又從新開闢了n個西瓜地。
爲了能給他的n個西瓜地順利的澆上水,對於每一個西瓜地他能夠選擇在本地打井,也能夠修管道從另外一個瓜地(這個瓜地可能打了井;也可能沒打井,他的水也是從其餘瓜地引來的)將水引過來。
固然打井和修管道的費用有差異。已知在第i個西瓜地打井須要耗費wi元,在第i、j個西瓜地之間修管道須要耗費pi,j元。
如今的問題是:王大爺要想使全部瓜地都被澆上水,至少須要花費多少錢(打井與修管道的費用和)?
因爲瓜地較多,王大爺沒法選擇在哪些(個)瓜地打井,哪些西瓜地之間修管道。
請你編程幫王大爺作出決策,求出最小費用。函數
第1行,一個正整數n,表明西瓜地的數量。
如下n行,依次給出整數w1..wn(每塊西瓜地的打井費用)。
緊接着是一個n*n的整數矩陣,矩陣的第i行第j列的數表明pi,j(兩塊西瓜地之間創建管道的費用)。每行的兩個數之間有一個空格隔開。spa
6 5 4 4 3 1 20 0 2 2 2 9 9 2 0 3 3 9 9 2 3 0 4 9 9 2 3 4 0 9 9 9 9 9 9 0 9 9 9 9 9 9 0
在第4個瓜地打井(費用爲3),而後將第2,3,4個瓜地與第1個瓜地間修管道(費用分別是2,2,2),這樣水能夠通過管道從4流向1,而後經1再流向2和3;
在第5個瓜地打井(費用爲1),5和6之間修管道(費用爲9)。
這樣一共打了2口井,修了4條管道,能給全部的6個瓜地澆水,費用是:3+2+2+2+1+9=19。 .net
對於全部數據,1<=N<=300,1<=wi<=100000;pi,i=0,1<=pi,j=pj,i<=100000。code
應用貪婪算法,先在打井費用最便宜的地打井,用已有水源的地更新沒有水源的地(判斷二者之間是否適合挖管道),若全部地都有水源,算法結束,不然,打下一口井blog
參考博客:https://blog.csdn.net/dmgy110/article/details/50637401#include <stdio.h> int flg[1000]; /*保存打井或者挖管道信息,0挖管道,1打井 */ int barr[1000][1000]; int arr[1000]; void update(int *st, int n); int find(int *arr, int n, int last)/*找出打井費用最低的地*/ { int i; int min = arr[1]; int rt = 1; for (i = 2; i < n + 1; i++) if (arr[i] < min && arr[i] > last) { min = arr[i]; rt = i; } return rt; } int check(int *a, int n)/*檢查當前全部土地是否都有水源*/ { int i; for (i = 1; i < n + 1; i++) { if (a[i] > 0) ; else break; } if (i == n + 1) return 0; else return 1; } int main(void) { int i, j, k; int n; if (freopen("water.in", "r", stdin) == NULL) return -1; scanf("%d", &n); int st[n + 1]; /*保存有水源的地打井或者挖管道的費用 */ for (i = 1; i < n + 1; i++) scanf("%d", &arr[i]); for (i = 1; i < n + 1; i++) for (j = 1; j < n + 1; j++) scanf("%d", &barr[i][j]); for (i = 0; i < n + 1; i++) { st[i] = 0; flg[i] = 0; } k = find(arr, n, 0); while (check(st, n) != 0) { if (st[k] == 0) { st[k] = arr[k]; flg[k] = 1; printf("第%d塊地打井 \n", k); } for (i = 1; i < n + 1; i++) { if (st[i] > 0) continue; int flag = 1; if (i == k || barr[i][k] > arr[i]) continue; else { for (j = 1; j < n + 1; j++) { if (i != j && barr[i][j] < barr[i][k] && j != k) { flag = 0; break; } } if (flag == 1 && st[i] == 0) { st[i] = barr[i][k]; printf ("第%d塊地與第%d塊地挖管道\n", i, k); } } } update(st, n); k = find(arr, n, st[k]); } for (i = 1; i < n + 1; i++) printf("%d ", st[i]); printf("\n"); return 0; } /*當i塊地接通水源之後別的地能夠經過與挖它管道接通水源 * 本函數做用是肯定沒有水源的地與i塊地之間的管道*/ void update(int *st, int n) { int i, j, k, l; for (l = 1; l < n + 1; l++) { if (st[l] > 0 && flg[l] == 0) k = l; else continue; for (i = 1; i < n + 1; i++) { if (st[i] > 0 && flg[i] == 1) /*flg[i]=1,打井的地,費用信息不能更新 */ continue; int flag = 1; /*跳過與第i塊間管道費用比打井貴的地 */ if (i == k || barr[i][k] > arr[i]) continue; else { /**/ for (j = 1; j < n + 1; j++) { if (i != j && barr[i][j] < barr[i][k] && j != k) { flag = 0; break; } } if (flag == 1 && st[i] == 0 && flg[i] == 0) { st[i] = barr[i][k]; printf ("第%d塊地與第%d塊地挖管道\n", i, k); } } } } }