zoukankan      html  css  js  c++  java
  • ACM/ICPC 之 BFS范例(ZOJ2913-ZOJ1136(POJ1465))

    通过几道经典BFS例题阐述BFS思路


    ZOJ2913-Bus Pass

      题意:找一个center区域,使得center到所有公交线路最短,有等距的center则输出id最小的。

      题解:经典的BFS,由公交线路最多只经过10*20个区域,而总区域数可达10^5个,因此应该从公交线路通过队列一层层向外扩展,最后判断一次center的位置即可。

     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
    ", minstep, minid);
    87     }
    88 
    89     return 0;
    90 }

    ZOJ1136(POJ1465)-Multiple

      题意:找出m个十进制数字所组成的n的倍数的最小值

      题解:依次枚举每一位上的数字进行BFS搜索,并利用初等数论同余的性质进行剪枝。

        现在阐述有关同余剪枝的算法:

          如果有两个数a,b = n*k+c  (k为任意整数),即a%n = b%n = c

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

            如果枚举的下一位数字为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("
    ");
    47                     return;
    48                 }
    49             }
    50         }
    51         front++;
    52     }
    53     
    54     printf("0
    ");
    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
    ");
    64             continue;
    65         }
    66         sort(dig, dig + m);
    67         bfs();
    68     }
    69     return 0;
    70 }
    他坐在湖边,望向天空,她坐在对岸,盯着湖面
  • 相关阅读:
    根据View找控制器
    ScrollView双击图片定点放大
    iOS消息推送原理和实现总结
    iOS完整学习路线图
    获取设备版本
    UIView与CALayer的区别,很详细
    iOS开发网络数据之AFNetworking使用
    (已实践)PLSQL本地还原Oracle数据库dmp文件
    所遇Oracle错误代码
    Dapper基本使用
  • 原文地址:https://www.cnblogs.com/Inkblots/p/5297259.html
Copyright © 2011-2022 走看看