• [NOIP 2002普及组]产生数(floyd+高精度)


    https://www.luogu.org/problem/P1037

    题目描述

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

    输入描述:

    输入格式为:
    n k

    x1 y1

    x2 y2

    ... ...

    xn yn

    输出描述:

    一个整数(满足条件的个数)

    示例1

    输入

    234 2
    2 5
    3 6

    输出

     4

    多给一组数据吧,我第一次写的就这个没过

    输入

    12345678901234567890 9
    2 1
    3 2
    4 3
    5 4
    6 5
    7 6
    8 7
    9 8
    0 9

    输出

    13168189440000

    注意点:

    1、一共有15种操作  说明一个数可以变成多个不同的数

    如果存在 2个操作 a->b   b->c   则a既可以变到b也可以变到c

    所以可以通过DFS或floyd求出每个数字可以变成多少种数字

    2、最多可能有30位数 所以最大可能9^30

    需要模拟大数乘法 而每次乘数有一个 不超过10 所以并不难

    故floyd+高精度秒杀,用floyd求出每个数字可以变成多少种数字,然后乘起来

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <iostream>
     4 #include <string>
     5 #include <math.h>
     6 #include <algorithm>
     7 #include <vector>
     8 #include <queue>
     9 #include <set>
    10 #include <map>
    11 #include <math.h>
    12 const int INF=0x3f3f3f3f;
    13 typedef long long LL;
    14 const int mod=1e9+7;
    15 const double PI=acos(-1);
    16 const int maxn=100010;
    17 using namespace std;
    18 //ios::sync_with_stdio(false);
    19 //    cin.tie(NULL);
    20 
    21 int k;
    22 char str[50];
    23 int tag[10][10];//tag[i][j]=1代表数字i可变成j 
    24 int num[10];//存放每个数字可变换数字的个数 
    25 int ans[1000];//答案 
    26 
    27 int main()
    28 {
    29     scanf("%s %d",str,&k);
    30     for(int i=1;i<=k;i++)
    31     {
    32         int a,b;
    33         scanf("%d %d",&a,&b);
    34         tag[a][b]=1; 
    35     }
    36     for(int k=1;k<=9;k++)//floyd 
    37     {
    38         for(int i=0;i<=9;i++)
    39         {
    40             for(int j=0;j<=9;j++)
    41             {
    42                 if(tag[i][k]&&tag[k][j])
    43                     tag[i][j]=1;
    44             }
    45         }
    46     }
    47     for(int i=0;i<=9;i++)
    48     {
    49         tag[i][i]=1;
    50         for(int j=0;j<=9;j++)
    51         {
    52             if(tag[i][j])
    53                 num[i]++;
    54         }
    55     }
    56     //高精度乘法 
    57     ans[0]=1;//初始答案 
    58     int jinwei;//进位 
    59     int weishu=1;//位数 
    60     for(int i=0;str[i];i++)
    61     {
    62         jinwei=0;
    63         int x=num[str[i]-'0'];//该位置数字可变多少种数字 
    64         for(int j=0;j<weishu;j++)
    65         {
    66             int t=ans[j]*x+jinwei;
    67             ans[j]=t%10;
    68             jinwei=t/10;
    69         }
    70         while(jinwei)
    71         {
    72             ans[weishu++]=jinwei%10;
    73             jinwei/=10;
    74         }
    75     }
    76     for(int i=weishu-1;i>=0;i--)//注意要反着输出 
    77     {
    78         printf("%d",ans[i]);
    79     }
    80     printf("
    ");
    81     return 0;
    82 }

    下面粘另一种写法,主要用了DFS,复杂度可能小一点(from:https://blog.csdn.net/AXuan_K/article/details/41479705)

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 int op[10][10];           
     6 char str[105];
     7 int vis[10];
     8 int value[32];
     9 int maxlen=1;
    10 void dfs(int a)         //搜索出每个数可以到达的数的个数   用SS保存
    11 {
    12     if(vis[a])
    13         return;
    14     vis[a]=1;
    15     ss++;
    16     for(int i=0;i<=9;i++)
    17     {
    18         if(op[a][i]==1)
    19             dfs(i);
    20     }
    21 }
    22 void multiple(int x)             //最大可能 9^30 超long long  所有模拟大数乘法
    23 {
    24     int carry=0;                 //carry表示进位
    25     for(int i=1;i<=maxlen;i++)
    26     {
    27         value[i]=value[i]*x+carry;
    28             carry=value[i]/10;
    29             value[i]=value[i]%10;
    30     }
    31     if(carry>0)               
    32         value[++maxlen]=carry;
    33     return;
    34 }
    35 int main()
    36 {
    37     int m,n,i,j,k;
    38     int s;
    39     value[1]=1;
    40     memset(op,0,sizeof(op));
    41     scanf("%s%d",str,&k);
    42     int a,b;
    43     if(k==0)               
    44     {
    45         cout<<1<<endl;
    46         return 0;
    47     }
    48     while(k--)
    49     {
    50         scanf("%d%d",&a,&b);
    51         op[a][b]=1;               //op[a][b]代表a可以到b
    52     }
    53     int len=strlen(str);
    54     for(i=0;i<len;i++)
    55     {
    56         memset(vis,0,sizeof(vis));
    57         ss=0;
    58         dfs(str[i]-'0');          //求出每位可转换数的乘积   //其实可以用一个数组保存每个数可转换的数的个数  
    59         multiple(ss);
    60     }
    61     for(i=maxlen;i>=1;i--)
    62         cout<<value[i];
    63     cout<<endl;
    64     return 0;
    65 }
  • 相关阅读:
    android:id="@android:id/tabhost" 、android:id="@+id/llRoot" 、android:id="@id/llRoot" 之间的区别
    android:ellipsize的使用
    PopupWindow为什么要设置setBackgroundDrawable(new BitmapDrawable());
    android中LayoutInflater的3种使用以及getSystemService的API
    context 的理解
    Android 中this、getContext()、getApplicationContext()、getApplication()、getBaseContext() 之间的区别
    android Matrix 使用
    public private protected frientdly 作用域
    pyinstaller参数介绍以及总结
    MongoDB高级查询详细
  • 原文地址:https://www.cnblogs.com/jiamian/p/11386006.html
Copyright © 2020-2023  润新知