zoukankan      html  css  js  c++  java
  • ZOJ 1136 Multiple BFS 取模 POJ 1465

    该题的关键是如果a%n = x;

    则(a*10+b)%n == (x*10+b)%n。例如你要算123456789%3,你只需算((12345678%n)*10+9)%3。

    想法是把给你的数字先排序,然后扩展,这样能保证你拓展出的数是以递增序列出现的。按示例所示,给你数字1,7,0,你可以拓展出10,11,17;70,71,77;

    从拓展出的六个新的数,每个数又能拓展出M(这里的M为3)个。然后要优化处理,算所谓的剪枝吧。拓展出的数模n的余数等于原数的余数*10+增加的数,再模n.

    如果新数的余数已经出现过,就不入队列了,因为该数没有被拓展的必要(已经有一个比它小的数用来拓展)。如果出现某数的余数为0,循环结束,输出该数。如果队列空了,证明一直没有拓展出新的余数,那么再拓展下去也不会有新的余数出现,这样证明不存在这样的数,输出0.

    下面的代码可以过ZOJ,因为ZOJ给了10s的时间。但是POJ不能过,因为POJ的时间限制是1s.

    View Code
     1 #include <cstdio>
     2 #include <queue>
     3 #include <string>
     4 #include <cstring>
     5 #include <iostream>
     6 #include <algorithm>
     7 using namespace std;
     8 int p[10];    //出现的数字按从小到大放在p中
     9 int N,M;
    10 bool v[5005];   //记录出现过的余数
    11 struct node
    12 {
    13     int res;  //该字符串的余数
    14     string s;
    15 };
    16 string BFS()
    17 {
    18     queue<node> Q;
    19     memset(v,false,sizeof(v));
    20     for(int i=0; i < M; i++) //预处理
    21     {
    22         if(p[i] == 0) continue;  //0不入队列,不用0来拓展
    23         node ss ;
    24         ss.res = p[i]%N;
    25         ss.s = ss.s + (char) (p[i]+'0');
    26         if(ss.res == 0)  return ss.s;  //出现余数 0,返回
    27         if(v[ss.res]) continue;  //该余数出现过
    28         v[ss.res] = true;
    29         Q.push(ss);  //入队列
    30     }
    31     while(!Q.empty())  //非空
    32     {
    33         node s ;
    34         s = Q.front();
    35         Q.pop();
    36         for(int j=0; j < M; j++)  //每个pop出的数用来拓展出M个数
    37         {
    38             node t;
    39             t.res = (s.res*10 + p[j])%N;
    40             t.s = s.s+(char)('0'+p[j]);  //拓展的数直接在原数后加一位数
    41             if(t.res == 0)                return t.s;  //出现余数0,返回
    42             if(v[t.res])  continue;  //余数出现过,不入队列
    43             v[t.res] = true;  //新余数,标记为true
    44             Q.push(t);
    45         }
    46     }
    47     return "0";
    48 }
    49 int main()
    50 {
    51     while(scanf("%d",&N) != EOF)
    52     {
    53         scanf("%d",&M);
    54         for(int i= 0 ; i < M; i++)
    55             scanf("%d",&p[i]);
    56         if(N==0)  //特判0
    57         {
    58             printf("0\n");
    59             continue;
    60         }
    61         sort(p,p+M);  //排序
    62         cout<<BFS()<<endl;
    63     }
    64     return 0;
    65 }

     因为上面在保存被拓展出来的数时整个数都被保存了,事实上是没有必要的,只需要记录这个数的前一位是谁就行了,比如4535,我不需要保存4535,我只要知道5的前面是3,3的前面是5,这个5的前面是4,而4535是由453拓展出来的,453是由45拓展出来的,45是由4拓展出来的。这样就能节省内存和时间了,就像记录路径一样,给每个被拓展的数除了有个编号,还添加int pre,和int now, now表明拓展时我加的数字,pre表示是由哪个数字拓展出来的,那么该数字的now值就是我的前一位了。回到上面的例子,数字4535的now值是5,pre值是数字453的编号,数字453的now值是3,pre值是45的编号,以此类推。

    贴代码:

    View Code
     1 #include <cstdio>
     2 #include <string>
     3 #include <cstring>
     4 #include <iostream>
     5 #include <algorithm>
     6 using namespace std;
     7 int p[10];    //出现的数字按从小到大放在p中
     8 int N,M;
     9 bool v[5005];   //记录出现过的余数
    10 struct node
    11 {
    12     int res;  //该字符串的余数
    13     int pre;
    14     char now;
    15 };
    16 void BFS()
    17 {
    18     node Q[6000];
    19     int head=0,tail=0;
    20     memset(v,false,sizeof(v));
    21     for(int i=0; i < M; i++) //预处理
    22     {
    23         if(p[i] == 0) continue;  //0不入队列,不用0来拓展
    24         node  ss ;
    25         ss.res = p[i]%N;
    26         ss.pre = -1;
    27         ss.now = p[i];
    28         if(ss.res == 0)  //出现余数 0,返回
    29         {
    30             printf("%d\n",p[i]);
    31             return ;
    32         }
    33         if(v[ss.res]) continue;  //该余数出现过
    34         v[ss.res] = true;
    35         Q[tail] = ss;
    36         tail++;
    37     }
    38     while(head != tail)  //非空
    39     {
    40         node s ;
    41         s= Q[head] ;
    42         for(int j=0; j < M; j++)  //每个pop出的数用来拓展出M个数
    43         {
    44             node t;
    45             t.res = (s.res*10 + p[j])%N;
    46             t.pre = head;  //拓展的数直接在原数后加一位数
    47             t.now = p[j] ;
    48             if(t.res == 0)        //出现余数0,返回
    49             {
    50                 int cur = 0;
    51                 node re  = t;
    52                 char d[1000];
    53                 while(re.pre !=-1)
    54                 {
    55                     d[cur++] = re.now;
    56                     re = Q[re.pre];
    57                 }
    58                 d[cur++] = re.now;
    59                 for(int i=cur-1; i>=0; i--)
    60                     printf("%d",d[i]);
    61                 printf("\n");
    62                 return ;
    63             }
    64             if(v[t.res])  continue;  //余数出现过,不入队列
    65             v[t.res] = true;  //新余数,标记为true
    66             Q[tail] = t;
    67             tail++;
    68         }
    69         head++;
    70     }
    71     printf("0\n");
    72     return ;
    73 }
    74 int main()
    75 {
    76     while(scanf("%d",&N) != EOF)
    77     {
    78         scanf("%d",&M);
    79         for(int i= 0 ; i < M; i++)
    80             scanf("%d",&p[i]);
    81         if(N==0)  //特判0
    82         {
    83             printf("0\n");
    84             continue;
    85         }
    86         sort(p,p+M);  //排序
    87         BFS();
    88     }
    89     return 0;
    90 }
  • 相关阅读:
    Android&Handler2
    ACM&数字阶梯求和(大数问题)
    Android&MyThread
    【转】 《基于MFC的OpenGL编程》Part 15 Selection
    【转】 《基于MFC的OpenGL编程》Part 12 Creating and Using Display Lists
    【转】《基于MFC的OpenGL编程》Part 16 Reflection
    【转】 《基于MFC的OpenGL编程》Part 8 Colors
    【转】 《基于MFC的OpenGL编程》Part 14 Quadrics
    开发不同语言版本的C#程序
    基于ADS40的线阵摄影测量及数据处理
  • 原文地址:https://www.cnblogs.com/allh123/p/2979401.html
Copyright © 2011-2022 走看看