ACM/ICPC 之 BFS範例(ZOJ2913-ZOJ1136(POJ1465))

經過幾道經典BFS例題闡述BFS思路ios

 


 

ZOJ2913-Bus Pass算法

 

  題意:找一個center區域,使得center到全部公交線路最短,有等距的center則輸出id最小的。spa

  題解:經典的BFS,由公交線路最多隻通過10*20個區域,而總區域數可達10^5個,所以應該從公交線路經過隊列一層層向外擴展,最後判斷一次center的位置便可。code

 

 1 //選定一個center使得其到全部公交線路最短
 2 //對全部公交線路進行BFS(公交線路比其餘區域少得多)
 3 //Time:150Ms    Memory:2840K
 4 #include<iostream>
 5 #include<cstring>
 6 #include<cstdio>
 7 #include<queue>
 8 #include<vector>
 9 using namespace std;
10 
11 #define MAX 10005
12 #define max(x,y) ((x)>(y)?(x):(y))
13 
14 int nz, nr;
15 int td[MAX];    //臨時距離記錄-並充當已訪問記錄
16 int d[MAX];    //總距離記錄
17 bool trip[MAX];    //記錄全部公交線路
18 vector<int> zones[MAX];    //鄰接表
19 
20 void bfs(int x)
21 {
22     memset(td, 0, sizeof(td));
23     queue<int> qz;    //queue_zones
24     td[x] = 1;
25     qz.push(x);
26     while (!qz.empty())
27     {
28         int cur = qz.front();
29         qz.pop();
30         for (int i = 0; i < zones[cur].size(); i++)
31         {
32             int adj = zones[cur].at(i);
33             if (!td[adj]) {
34                 td[adj] = max(td[adj], td[cur] + 1);
35                 qz.push(adj);
36             }
37         }
38         d[cur] = max(d[cur], td[cur]);
39     }
40 }
41 
42 int main()
43 {
44     int T;
45     scanf("%d", &T);
46     while (T--)
47     {
48         //Init
49         memset(trip, false, sizeof(trip));
50         memset(d, 0, sizeof(d));
51         memset(zones, 0, sizeof(zones));
52 
53         //Input
54         scanf("%d%d", &nz, &nr);
55         for (int i = 0; i < nz; i++)
56         {
57             int id, adj;    //adjacent
58             scanf("%d%d", &id, &adj);
59             while (adj--) {
60                 int num;
61                 scanf("%d", &num);
62                 zones[id].push_back(num);
63             }
64         }
65         for (int i = 0; i < nr; i++)
66         {
67             int id,sum;
68             scanf("%d", &sum);
69             while (sum--)
70             {
71                 scanf("%d", &id);
72                 if (!trip[id]) {    //未遍歷過
73                     trip[id] = true;    //記錄爲公交線路
74                     bfs(id);
75                 }
76             }
77         }
78         
79         //Output
80         int minstep = MAX;
81         int minid;
82         for (int i = 0; i < MAX; i++)
83             if (d[i] && minstep > d[i])
84                 minstep = d[minid = i];    //保證id最小+最小距離
85 
86         printf("%d %d\n", minstep, minid);
87     }
88 
89     return 0;
90 }

 


 

 

ZOJ1136(POJ1465)-Multipleblog

 

  題意:找出m個十進制數字所組成的n的倍數的最小值遞歸

  題解:依次枚舉每一位上的數字進行BFS搜索,並利用初等數論同餘的性質進行剪枝。隊列

    如今闡述有關同餘剪枝的算法:ip

      若是有兩個數a,b = n*k+c  (k爲任意整數),即a%n = b%n = crem

        假定n = 11,a = 24,b = 35,此時c=2string

        若是枚舉的下一位數字爲2,則a = 242,恰好是n的倍數,而b = 352也恰好是n的倍數

      這樣的狀況不是偶然,對於廣泛狀況 a,b = n*k + c  (k爲任意整數)

        恆有(a*10 + m)%n == (b*10 + m)%n

    即:增長一位數後,n的同餘數依然是同餘數

    所以在進行BFS時,只須要對「全部同餘數的最小值」考慮便可。

 

 1 //給出n,求能使所給的數字組成n的倍數的最小值
 2 //BFS+數論(同餘剪枝)
 3 //Time:47Ms    Memory:184K
 4 #include<iostream>
 5 #include<cstring>
 6 #include<cstdio>
 7 #include<algorithm>
 8 using namespace std;
 9 #define MAXN 5000
10 struct NUM {
11     int dig;
12     int rem;
13     int fa;        //父節點
14 }num[MAXN];
15 int n, m;
16 int dig[10];
17 bool v[MAXN];    //餘數記錄
18 //遞歸輸出
19 void output(int x)
20 {
21     if (num[x].fa)
22         output(num[x].fa);
23     printf("%d", num[x].dig);
24 }
25 void bfs()
26 {
27     memset(v, false, sizeof(v));
28     int front = 0, tail = 0;
29     num[0].rem = num[0].dig = 0;
30     num[0].fa = NULL;
31     while (front <= tail)
32     {
33         NUM t;
34         t.fa = front;
35         for (int i = 0; i < m; i++)    //逐次枚舉下一個數字
36         {
37             t.rem = (num[front].rem * 10 + dig[i]) % n;
38             if (!v[t.rem] && (t.rem || front))    //排除同餘數
39             {
40                 v[t.rem] = true;
41                 t.dig = dig[i];
42                 num[++tail] = t;
43                 if (t.rem == 0)
44                 {
45                     output(tail);
46                     printf("\n");
47                     return;
48                 }
49             }
50         }
51         front++;
52     }
53     
54     printf("0\n");
55 }
56 int main()
57 {
58     while (scanf("%d%d", &n, &m) != EOF)
59     {
60         for (int i = 0; i < m; i++)
61             scanf("%d", &dig[i]);
62         if (n == 0) {    //n=0的時候要麼不存在此倍數,要麼就爲0,所以可直接輸出0
63             printf("0\n");
64             continue;
65         }
66         sort(dig, dig + m);
67         bfs();
68     }
69     return 0;
70 }
相關文章
相關標籤/搜索