zoukankan      html  css  js  c++  java
  • P1037 产生数(洛谷)

    题目传送门

      最开始错误的思路是对整条字串进行dfs,看一位dfs进入下一位,这是没有充分理解题意的后果
     
      核心解题思路:不要被这些规则变来变去搞混了,我们需要将原问题进行切割成小的子问题去分析。例如此处我们将每一位数都当做一个独立单位,首先求出在这个位置上有多少种可以存在的数的种类(0~9)。而这些独立单位(位置)互不相同,彼此独立,因此求出总的可变换的数的总数则是每个位置上的数的种类的累乘。对每一位上的数操作时,把变换的规则当做是点与点的连接(一共有10个点位0~9)。因此想要访问所有能走的点(有多少点则有个种类的数),因此这一遍历全部图的思想符合dfs的性质

      注意:在数的第一个位置上,我们假设0的存在是合法的,比如0123实际上是123,但它也带来了一个新的数字,因此种类也会增加
     
     
    实现代码:
     
     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define lll __uint128_t
     4 
     5 char s[100];        //用于储存整数 
     6 int memory[100]={0};            //用于数有多少种变换种类    实质是一个优化,记忆化储存 
     7 lll ans;             //用于储存数的种类 
     8 int num=0;            //记录每个位置上有多少种类数 
     9 int flag[100]={0};        //用于dfs中标志     同样直接拿字符'0'~'9'当做下标 
    10 int k=0;                //规则数 
    11 char a[20],b[20];            //储存变换规则
    12  
    13 void out(lll x){//int128输出要自己写 
    14     if(x>9)out(x/10);
    15     putchar(x%10+48);
    16 }
    17 void dfs(char index){
    18     flag[index]=1;        //走过标记为1
    19     num++;                //访问到一个点就加一
    20     
    21     for(int i=1;i<=k;i++){
    22         if(index==a[i]){
    23             if(flag[b[i]])    continue;        //访问过                
    24             dfs(b[i]);
    25             //这里不能加上回溯,因为不会重复访问同一个点 
    26         } 
    27     } 
    28     return ;
    29     
    30 } 
    31 int main(){
    32     ios::sync_with_stdio(false);        //加快数据的输入和输出 
    33     cin.tie(0);
    34     cout.tie(0);
    35     ans=1;        //初始化为1
    36     
    37     cin>>s>>k;
    38     for(int i=1;i<=k;i++){
    39         cin>>a[i]>>b[i];
    40     }
    41     
    42     for(int i=0;s[i]!='';i++){        //对于每一位数去操作 
    43         num=0;
    44         if(memory[s[i]]){                    //直接拿ascii码当下标,懒得去转为数字 
    45             num=memory[s[i]];                //表示之前已经搜过相同的数了,结果存在数组a中 
    46         }else{                            //表示没搜过第一次搜 
    47             memset(flag,0,sizeof(flag));
    48             dfs(s[i]); 
    49             memory[s[i]]=num;                //储存下来 
    50         }
    51         ans*=num;
    52     } 
    53     out(ans);        //输出种类数 
    54     return 0;
    55 }

    补充说明:__uint128_t是一个较大的类型,而且符合gcc标准,在很多oj平台上可以使用。但其输出函数不能用cout或者printf,需要自己重写。详细解释见:这里。

    如果不用此类型,则需要高精度乘法算法来实现程序。

  • 相关阅读:
    传说中的灵感
    错误: Sys.WebForms.PageRequestManagerServerErrorException: 只能在执行 Render() 的过程中调用 RegisterForEventValidation;
    只能在执行 Render() 的过程中调用 RegisterForEventValidation
    在aspx实现用户控件内Web控件的事件
    Asp.net网页上嵌入Media Player播放
    为临时表动态添加字段
    如何防止头文件被重复包含、嵌套包含
    Linux C SQLite3 编程
    Android开源项目源码下载(不断更新中)
    Android程序员必看之Android六大优势
  • 原文地址:https://www.cnblogs.com/xwh-blogs/p/12607850.html
Copyright © 2011-2022 走看看