zoukankan      html  css  js  c++  java
  • 1009 产生数 2002年NOIP全国联赛普及组

    1009 产生数

    2002年NOIP全国联赛普及组

    时间限制: 1 s
    空间限制: 128000 KB
    题目等级 : 黄金 Gold
     
    题目描述 Description

      给出一个整数 n(n<10^30) 和 k 个变换规则(k<=15)。
      规则:
       一位数可变换成另一个一位数:
       规则的右部不能为零。
      例如:n=234。有规则(k=2):
        2-> 5
        3-> 6
      上面的整数 234 经过变换后可能产生出的整数为(包括原数):
       234
       534
       264
       564
      共 4 种不同的产生数
    问题:
      给出一个整数 n 和 k 个规则。
    求出:
      经过任意次的变换(0次或多次),能产生出多少个不同整数。
      仅要求输出个数。

    输入描述 Input Description

    键盘输人,格式为:
       n k
       x1 y1
       x2 y2
       ... ...
       xn yn

    输出描述 Output Description

     屏幕输出,格式为:
      一个整数(满足条件的个数)

    样例输入 Sample Input


       234 2
       2 5
       3 6

    样例输出 Sample Output

    4

    数据范围及提示 Data Size & Hint
     

    思路:

      符合变换规则的数可以在变换一次后的新数仍然符合变换规则

      所以我们考虑将之转化为一个图论问题

      就是考虑从i到j需要经过多少点

      经过的点的个数就是可以变换成的数

      可是怎么求呢?

      用弗洛伊德算法

      弗洛伊德是个n^3的动态规划

      枚举三个点i,j,k

      如果i到j的距离大于i到k加上k到i的距离就会更新i到j的距离

      根据这个原理我们可以增加一个计数器

      即每更新一次i到j的距离则i的变换数的个数加1

      因为n的本身也算是一种排列

      所以所有数的变换个数初始为1、

      将所有的变换数的个数都求出后

      可以通过相乘的积得出总个数

     
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 using namespace std;
     5 long long ans=1,num[10];
     6 int n,map[10][10];
     7 char cur[50];
     8 int main()
     9 {
    10     memset(map,127/3,sizeof(map));
    11     scanf("%s",cur);
    12     scanf("%d",&n);
    13     for(int a,b,i=1;i<=n;i++)
    14     {
    15         scanf("%d%d",&a,&b);
    16         map[a][b]=1;
    17     }
    18     for(int k=0;k<=9;k++)
    19     {
    20         for(int i=0;i<=9;i++)
    21         {
    22             for(int j=0;j<=9;j++)
    23             {
    24                 if(i!=j&&j!=k&&k!=i)
    25                 if(map[i][k]+map[k][j]<map[i][j])
    26                 {
    27                     map[i][j]=map[i][k]+map[k][j];
    28                 }
    29             }
    30         }
    31     }
    32     for(int i=0;i<=9;i++)
    33     {
    34         num[i]++;
    35         for(int j=0;j<=9;j++)
    36         {
    37             if(j==i) continue;
    38             if(map[i][j]<10000) num[i]++;
    39         }
    40     }
    41     for(int i=0;i<strlen(cur);i++) ans=(ans*num[(int)(cur[i]-'0')]);
    42     cout<<ans<<endl;
    43     return 0;
    44 }
  • 相关阅读:
    实时信号阻塞队列大小测试
    实时信号和非实时信号
    [Linux]关于sigprocmask函数的讨论
    java中Map集合的常用方法 (转)
    佛跳墙
    百万数据查询效率提高方法(转)
    bootstrap table 前后端分页(超级简单)
    bootstrap table 分页序号递增问题 (转)
    Spring boot+mybatis+thymeleaf 实现登录注册,增删改查
    js弹出对话框的三种方式(转)
  • 原文地址:https://www.cnblogs.com/mjtcn/p/6735392.html
Copyright © 2011-2022 走看看