Interview street, 王國連通問題

Interviewstreet Challenge

Kingdom Connectivity

It has been a prosperous year for King Charles and he is rapidly expanding his kingdom. a beautiful new kingdom has been recently constructed and in this kingdom there are many cities connected by a number of one-way roads. Two cities may be directly connected by more than one roads, this is to ensure high connectivity.

對於 Charles 國王來說,這是成功的一年,他迅速的擴展了他的王國。一個美麗的王國最近建立了,在這個王國中有許多城市通過許多單行道連通起來。兩個城市可以直接通過多於一條路來連通,這是爲了確保更高的連通性。

In this new kingdom King Charles has made one of the cities at his financial capital and one as warfare capital and he wants high connectivity between these two capitals. The connectivity of a pair of cities say city A and city B is defined as the number of different paths from city A to city B. A path may use a road more than once if possible. Two path are considered different if they do not use exactly the same sequece of roads.

在這個新的王國,國王 Charles 使一個城市作爲他的金融中心,另一個作爲戰爭中心,他想讓這兩個城市之間有更高的連通性。比方說城市A和城市B這一對城市的連通性由從城市A到城市B不同 路徑 的數目定義。如果可能的話,一個 路徑 可以多次使用一個道路。如果他們不精確地使用同一個道路序列,兩個路徑就是不同的。

There are N cities numbered 1 to N in the new kindom and M one-way roads. City 1 is the monetary captial and city N is the warare capital.

王國中有編號從1到N的N個城市和M條單行道。城市1是金融中心,城市N是戰爭中心。

You being one of he best programmers in new kindom need to answer the connectivity of financial capital and warfare capital, i.e number of different path from city 1 to city N.

你是王國中最好的計劃員之一,需要回答金融中心和戰爭中心的連通性,例如,從城市1到城市N之間不同路徑的數目。

Input Description

First line contains two integers N and M.

第一行包含兩個整數N和M。

Then follow M lines, each having two integers asy x and y, 1<=x,y<=N, indicating there is a road from city x to city y.

接到來的M行,每一行有兩個整數,例如x和y,1<=x,y<=N, 代表有一條從城市x到城市y的道路。

Output Description:

Print the number of different path from city 1 to city N modulo 1,000,000,000 (10^9). If there are infinitely many different paths print "INFINITE PATHS" (quotes are for clarity).

打印從城市1到城市N不同 路徑 的數目 (不知道對誰求模)。如果有無窮多條不同 路徑 打印 "INFINITE PATHS" (引號是爲了清楚的說明)。


Sample Input:

5 5
1 2
2 4
2 3
3 4
4 5

Sample Output:

2

Sample Input:

5 5
1 2
4 2
2 3
3 4
4 5

Sample Output:

INFINITE PATHS

Constraints:

2<=N<=10,000(10^4)

1<=M<=1,00,000(10^5)


解題思路

好吧,我承認這道題我現在還沒有解決。

思路一

現在說說我的思路,初看題目我就感覺應該會用到圖論上的知識,但是我又沒怎麼學過離散數學,與於我就想,先不去看圖論方面的知識,只憑自己的直覺試試先。

我的 main 函數大概做了以下幾件事:

  1. 獲取數據
  2. 使用遞歸的方式獲取路徑數量 (path_num)

獲取數據就不用說了,我使用了一個結構體來保存,如下:


struct road {
    int from;
    int to;
    int times;
};

下面來說一說遞歸函數都做了點什麼。

遞歸函數 get_path_num()

這個函數邏輯是這樣的,從 目標城市N 開始,倒着查找 起始城市1 ,最終返回從 1 到 N 的不同路徑的數量。內部實現如下:

  • 找出 N 可由哪些城市到達,將可到達N的城市存爲一個列表,名爲from_list。
  • 檢查from_list中的每一個元素:比如城市 M,如果爲城市1,path_num加1,否則遞歸調用本身,返回從城市M開始倒着找到城市1的不同路徑的數量。

是不是沒看懂,這是因爲我說得也不清楚。如果真想清楚,只有看代碼了。下面的代碼是我第一次的實驗品,總共有10個test case,但只過了3個。我的建議是,不要看下面的代碼了,這段代碼邏輯不是十分清楚,並且還有bug。直接看我看過圖論知識後寫的第二段代碼吧。



  1. /** 
  2.  * @file kingdom_connectivity.c 
  3.  * @brief 
  4.  * @author Airead Fan <[email protected]> 
  5.  * @date 2012  3月 02 15:51:52 CST 
  6.  */ 
  7.  
  8. #include <stdio.h> 
  9. #include <stdlib.h> 
  10. #include <string.h> 
  11.  
  12. //#define _DEBUG_ 
  13.  
  14. #ifdef _DEBUG_ 
  15. #define DBG(fmt, args...) printf(fmt, ##args) 
  16. #else 
  17. #define DBG(fmt, args...) 
  18. #endif 
  19.  
  20. struct road { 
  21.     int from; 
  22.     int to; 
  23.     int times; 
  24. }; 
  25.  
  26. int city_num, road_num; 
  27.  
  28. /** 
  29.  * @brief get road list from stdin 
  30.  * @param road_num : the number of road 
  31.  * @return on error returns NULL, otherwise returns struct #road * 
  32.  */ 
  33. struct road *get_road_list(int road_num) 
  34.     int i; 
  35.     int size; 
  36.     struct road *road_list; 
  37.  
  38.     size = sizeof(struct road) * (road_num + 1); 
  39.     road_list = (struct road *)malloc(size); 
  40.     if (road_list == NULL) { 
  41.         printf("malloc failed\n"); 
  42.         return NULL; 
  43.     } 
  44.     memset(road_list, 0, size); 
  45.  
  46.     for (i = 0; i < road_num; i++) { 
  47.         scanf("%d %d", &road_list[i].from, &road_list[i].to); 
  48.     } 
  49.  
  50.     return road_list; 
  51.  
  52. /** 
  53.  * @brief get the list of city which can go to city 
  54.  * @param city : should go to city 
  55.  * @param road_list : all road in it 
  56.  * @return on error returns NULL, otherwise returns city_from_list 
  57.  */ 
  58. int *get_city_from_list(int city, struct road *road_list) 
  59.     int count, *city_from_list, *tmp_list; 
  60.     int size; 
  61.     struct road *road; 
  62.  
  63.     /* get from city list number to malloc */ 
  64.     count = 0; 
  65.     road = road_list; 
  66.     while (road->to != 0) { 
  67.         if (road->to == city) { 
  68.             count++; 
  69.         } 
  70.         road++; 
  71.     } 
  72.  
  73.     size = sizeof(int) * (count + 1); 
  74.     city_from_list = (int *)malloc(size); 
  75.     if (city_from_list == NULL) { 
  76.         printf("malloc city_from failed\n"); 
  77.         return NULL; 
  78.     } 
  79.     memset(city_from_list, 0, size); 
  80.  
  81.     /* set city_from_list */ 
  82.     road = road_list; 
  83.     tmp_list = city_from_list; 
  84.     while (road->to != 0) { 
  85.         if (road->to == city) { 
  86.             *tmp_list++ = road->from; 
  87.             road->times++; 
  88.             DBG("\n%d --> %d: times: %d\n", road->from, road->to, road->times); 
  89.         } 
  90.         road++; 
  91.     } 
  92.  
  93.     return city_from_list; 
  94.  
  95. /** 
  96.  * @brief get the number of path from city_from to city_to 
  97.  * @param city_start : start point of city 
  98.  * @param city_to : 
  99.  * @param road_list : 
  100.  * @param road_num : the number of road 
  101.  * @return on infinite returns -1, otherwise returns the number of path 
  102.  */ 
  103. int get_path_number(int city_start, int city_to, struct road *road_list, int road_num) 
  104.     int num, *city_from_list, tmp_num; 
  105.     int *pcity; 
  106.     struct road *road; 
  107.     static int target_from;            /* 
  108.                                         * if target city call 
  109.                                         * get_city_from_list, target_from set 1, 
  110.                                         * and don't call again 
  111.                                         */ 
  112.  
  113.     DBG("->%d", city_to); 
  114.  
  115.     num = 0; 
  116.  
  117.     if (city_to == city_num) { 
  118.         if (target_from == 0) { 
  119.             target_from = 1; 
  120.         } else { 
  121.             return 0; 
  122.         } 
  123.     } 
  124.  
  125.     city_from_list = get_city_from_list(city_to, road_list); 
  126.     if (city_from_list == NULL) { 
  127.         return 0; 
  128.     } 
  129.  
  130.     /* check infinite*/ 
  131.     road = road_list; 
  132.     while (road->to != 0) { 
  133.         if (road->times >= road_num) { 
  134.             DBG("%d --> %d: times: %d\n", road->from, road->to, road->times); 
  135.             return -1; 
  136.         } 
  137.         road++; 
  138.     } 
  139.  
  140.     pcity = city_from_list; 
  141.     while (*pcity != 0) { 
  142.         if (*pcity == city_start) { 
  143.             DBG("->%d", *pcity); 
  144.             num++; 
  145.         } else { 
  146.             tmp_num = get_path_number(city_start, *pcity, road_list, road_num); 
  147.             if (tmp_num < 0) { 
  148.                 return -1; 
  149.             } 
  150.             num += tmp_num; 
  151.         } 
  152.         pcity++; 
  153.     } 
  154.  
  155.     return num; 
  156.  
  157. int main(int argc, char *argv[]) 
  158.     int i, path_num; 
  159.     struct road *road_list; 
  160.  
  161.     scanf("%d %d", &city_num, &road_num); 
  162.     DBG("city_num = %d, road_num = %d\n", city_num, road_num); 
  163.  
  164.     road_list = get_road_list(road_num); 
  165.  
  166.     for (i = 0; i < road_num; i++) { 
  167.         DBG("road[%d]: %3d   --> %3d\n", i + 1, road_list[i].from, road_list[i].to); 
  168.     } 
  169.  
  170.     path_num = get_path_number(1, city_num, road_list, road_num); 
  171.     if (path_num < 0) { 
  172.         printf("INFINITE PATHS"); 
  173.     }else { 
  174.         printf("%d", path_num); 
  175.     } 
  176.  
  177.     free(road_list); 
  178.     return 0; 

思路2 (建議看這個)

這次我看了圖論相關的知識了。

先對題目進行分析,查看 output sample 可知,結果分成兩大類:一個是求出具體有幾條不同路徑,另一個是說明路徑是無限的。如果這個有向圖有圈的,就可以輸出無限了。否則的話,就要求出共有幾條不同的路徑。

判斷是否有無限路徑

定理: 設S爲有限的有向無圈圖,則圖S存在一個拓撲排序。

根據這個定理,我們可不可以認爲,一個不存在拓撲排序的的有向圖就是有圈的呢,我不是十分確定,但是我的代碼就是這樣判斷的。

拓撲排序的算法:

Step 1, 求S的每個頂點N的入度INDEG(N)
Step 2, 在隊列中插入所有的零度頂點
Step 3, 重複 Step 4 和 Step 5,直到隊列空
Step 4, 移去並檢查隊列的前面頂點N
Step 5, 對頂點N的每個鄰點M重複
        (a) 置INDEG(M) = INDEG(M) - 1
            [刪除從N到M的邊]
        (b) 若INDEG(M) = 0,則添加M到隊列
            [結束循環]
        [結束 Step 3 循環]
Step 6, 退出

求出有多少不同路徑

我的基本想法是:從城市1開始,檢查它所有的可達城市,如果爲目標城市則計數加1,否則檢查該城市的每一個可達城市,重複直到沒有可達城市爲止。比較類似於圖的深度優先算法吧。

這樣,我就可以走完從城市1所有能走的路徑,那麼當前的計數是否就應該爲 從城市1到城市N不同路徑的數量 呢?我覺得應該是的,但是結果是: 10個test case只過了2個,還沒有我上一個版本過的多,鬱悶死啦-_-。感興趣的同學可以討論一下這道題的解法。

題目來自:Interview street Kingdom Connectivity。不知道沒註冊能不能看。

第二個版本代碼如下:



  1. /** 
  2.  * @file kingdom_connectivity.c 
  3.  * @brief 
  4.  * @author Airead Fan <[email protected]> 
  5.  * @date 2012  3月 05 15:35:53 CST 
  6.  */ 
  7.  
  8. #include <stdio.h> 
  9. #include <stdlib.h> 
  10. #include <string.h> 
  11.  
  12. #define _DEBUG_ 
  13.  
  14. #ifdef _DEBUG_ 
  15. #define DBG(fmt, args...) printf(fmt, ##args) 
  16. #else 
  17. #define DBG(fmt, args...) 
  18. #endif 
  19.  
  20. struct point { 
  21.     int indeg; 
  22.     int outdeg; 
  23.     int status; 
  24.     struct edge *edge; 
  25. }; 
  26.  
  27. struct edge { 
  28.     int begin; 
  29.     int end; 
  30.     struct edge *next; 
  31. }; 
  32.  
  33. /** 
  34.  * @brief insert edge to point_list 
  35.  * @param point_list 
  36.  * @param begin 
  37.  * @param end 
  38.  * @return on success returns 0, otherwise returns -1 
  39.  */ 
  40. int point_list_insert_edge(struct point *point_list, int begin, int end) 
  41.     struct edge *tmpedge; 
  42.  
  43.     if ((tmpedge = malloc(sizeof(struct edge))) == NULL) { 
  44.         return -1; 
  45.     } 
  46.  
  47.     tmpedge->begin = begin; 
  48.     tmpedge->end = end; 
  49.     tmpedge->next = point_list[begin - 1].edge; 
  50.     point_list[begin - 1].edge = tmpedge; 
  51.  
  52.     point_list[begin - 1].outdeg++; 
  53.     point_list[end - 1].indeg++; 
  54.  
  55.     return 0; 
  56.  
  57. /** 
  58.  * @brief get point list from stdin 
  59.  * @param city_num 
  60.  * @return on error returns NULL, otherwise returns point_list 
  61.  */ 
  62. struct point *get_point_list(int city_num) 
  63.     struct point *point_list; 
  64.     int size; 
  65.  
  66.     point_list = NULL; 
  67.  
  68.     size = sizeof(struct point) * city_num; 
  69.     if ((point_list = malloc(size)) == NULL) { 
  70.         fprintf(stderr, "create point failed\n"); 
  71.         return NULL; 
  72.     } 
  73.     memset(point_list, 0, size); 
  74.  
  75.     return point_list; 
  76.  
  77. /** 
  78.  * @brief get edge list from stdin 
  79.  * @param edge_num 
  80.  * @return on error returns NULL, otherwise returns edge_list 
  81.  */ 
  82. struct edge *get_edge_list(int edge_num) 
  83.     struct edge *edge_list; 
  84.     int begin, end; 
  85.     int i, size; 
  86.  
  87.     edge_list = NULL; 
  88.  
  89.     size = sizeof(struct edge) * edge_num; 
  90.     if ((edge_list = malloc(size)) == NULL) { 
  91.         fprintf(stderr, "create edge failed\n"); 
  92.         return NULL; 
  93.     } 
  94.     memset(edge_list, 0, size); 
  95.  
  96.     for (i = 0; i < edge_num; i++) { 
  97.         scanf("%d %d", &begin, &end); 
  98.         edge_list[i].begin = begin; 
  99.         edge_list[i].end = end; 
  100.     } 
  101.  
  102.     return edge_list; 
  103.  
  104. /** 
  105.  * @brief find the point whose indeg is indeg 
  106.  * @param indeg 
  107.  * @param point_list 
  108.  * @param city 
  109.  * @return not found returns NULL, otherwise returns struct *point 
  110.  */ 
  111. struct point *find_point_from_indeg(int indeg, struct point *point_list, int city_num) 
  112.     int i; 
  113.     struct point *p; 
  114.  
  115.     for (i = 0; i < city_num; i++) { 
  116.         if (point_list[i].indeg == indeg && point_list[i].status == 0) { 
  117.             p = &point_list[i]; 
  118.             break
  119.         } 
  120.     } 
  121.  
  122.     if (i == city_num) { 
  123.         p = NULL; 
  124.     } 
  125.  
  126.     return p; 
  127.  
  128. /** 
  129.  * @brief check cyclic 
  130.  * @param point_list 
  131.  * @param city_num 
  132.  * @return not cyclic returns 0, otherwise returns 1; 
  133.  */ 
  134. int is_cyclic(struct point *point_list, int city_num) 
  135.     int i; 
  136.     struct point *p; 
  137.  
  138.     for (i = 0; i < city_num; i++) { 
  139.         point_list[i].status = 0; 
  140.     } 
  141.  
  142.     i = 0; 
  143.     while ((p = find_point_from_indeg(0, point_list, city_num)) != NULL) { 
  144.         p->status = 1; 
  145.         while (p->edge != NULL) { 
  146.             point_list[p->edge->end - 1].indeg--; 
  147.             p->edge = p->edge->next; 
  148.         } 
  149.         i++; 
  150.     } 
  151.  
  152.     if (i < city_num) { 
  153.         return 1; 
  154.     } 
  155.  
  156.     return 0; 
  157.  
  158. /** 
  159.  * @brief target is destination, path_num++ 
  160.  * @param point_list 
  161.  * @param city_num 
  162.  * @param path_num 
  163.  * @return on success returns 0, otherwise returns -1 
  164.  * 
  165.  * check the second parameter point 
  166.  */ 
  167. int check_target(struct point *point_list, int city, int city_num, int *path_num, char *trace) 
  168.     struct edge *tmpedge; 
  169.     char buf[32]; 
  170.  
  171.     snprintf(buf, 32, "%d->", city); 
  172.     strcat(trace, buf); 
  173.  
  174.     if (city == city_num) { 
  175.         DBG("%s\n", trace); 
  176.         (*path_num)++; 
  177.         trace[strlen(trace) - 3] = '\0'
  178.         return 0; 
  179.     } 
  180.  
  181.     tmpedge = point_list[city - 1].edge; 
  182.     while (tmpedge != NULL) { 
  183.         check_target(point_list, tmpedge->end, city_num, path_num, trace); 
  184.         tmpedge = tmpedge->next; 
  185.     } 
  186.  
  187.     trace[strlen(trace) - 3] = '\0'
  188.  
  189.     return 0; 
  190.  
  191. /** 
  192.  * @brief get the number of different paths 
  193.  * @param point_list 
  194.  * @param city_num 
  195.  * @param edge_num 
  196.  * @return on error returns -1, otherwise returns number; 
  197.  */ 
  198. int get_path_number(struct point *point_list, int city_num, int edge_num) 
  199.     int path_num; 
  200.     char trace[1024]; 
  201.  
  202.     memset(trace, 0, sizeof(trace)); 
  203.     path_num = 0; 
  204.     check_target(point_list, 1, city_num, &path_num, trace); 
  205.  
  206.     return path_num; 
  207.  
  208. int debug_point_list(struct point *point_list, int city_num) 
  209.     int i; 
  210.     struct edge *edge; 
  211.  
  212.     fprintf(stderr, "point | indeg | outdeg | target \n"); 
  213.  
  214.     for (i = 0; i < city_num; i++) { 
  215.         fprintf(stdout, "%3d   | %3d   | %4d   | ", i + 1, point_list[i].indeg, point_list[i].outdeg); 
  216.         edge = point_list[i].edge; 
  217.         while (edge != NULL) { 
  218.             fprintf(stdout, "%d, ", edge->end); 
  219.             edge = edge->next; 
  220.         } 
  221.         fprintf(stdout, "\n"); 
  222.     } 
  223.  
  224.     return 0; 
  225.  
  226. /** 
  227.  * @brief reset point list with edge list 
  228.  * @param point_list 
  229.  * @param edge_list 
  230.  * @param edge_num 
  231.  * @return on success returns 0, otherwise returns -1 
  232.  */ 
  233. int point_list_reset(struct point *point_list, struct edge *edge_list, int city_num, int edge_num) 
  234.     int i; 
  235.  
  236.     for (i = 0; i < edge_num; i++) { 
  237.         if (edge_list[i].begin == city_num) { 
  238.             DBG("ignore %d --> %d\n", edge_list[i].begin, edge_list[i].end); 
  239.             continue
  240.         } 
  241.         if (point_list_insert_edge(point_list, edge_list[i].begin, edge_list[i].end) < 0) { 
  242.             fprintf(stderr, "inset edge failed\n"); 
  243.             return -1; 
  244.         } 
  245.     } 
  246.  
  247.     return 0; 
  248.  
  249. int main(int argc, char *argv[]) 
  250.     int city_num, edge_num; 
  251.     struct point *point_list; 
  252.     struct edge *edge_list; 
  253.     int path_num; 
  254.  
  255.     scanf("%d %d", &city_num, &edge_num); 
  256.     DBG("city num: %d, edge num: %d\n", city_num, edge_num); 
  257.  
  258.     if ((point_list = get_point_list(city_num)) == NULL) { 
  259.         fprintf(stderr, "get point_list failed\n"); 
  260.         exit(1); 
  261.     } 
  262.  
  263.     if ((edge_list = get_edge_list(edge_num)) == NULL) { 
  264.         fprintf(stderr, "get edge_list failed\n"); 
  265.         exit(1); 
  266.     } 
  267.  
  268.     if (point_list_reset(point_list, edge_list, city_num, edge_num) < 0) { 
  269.         fprintf(stderr, "point list reset failed\n"); 
  270.         exit(1); 
  271.     } 
  272.  
  273.     debug_point_list(point_list, city_num); 
  274.  
  275.     if (is_cyclic(point_list, city_num) != 0) { 
  276.         fprintf(stdout, "INFINITE PATHS"); 
  277.         return 0; 
  278.     } 
  279.  
  280.     if (point_list_reset(point_list, edge_list, city_num, edge_num) < 0) { 
  281.         fprintf(stderr, "point list reset failed\n"); 
  282.         exit(1); 
  283.     } 
  284.  
  285.     path_num = get_path_number(point_list, city_num, edge_num); 
  286.  
  287.     fprintf(stdout, "%d", path_num); 
  288.     DBG("\n"); 
  289.  
  290.     return 0; 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章