• 3373Changing Digits


    我的代码是错的,第一次是超时,后来看了人家的代码,才知道原来可以用一个数组来节省时间

    我的错误的代码

    原因:

    搜索比n小的数字,此时为了搜索到的解 m 是最小的,应该从区间[0,s]的第s位开始向第0位搜索,因为在相同 pnum 情况下,把高位数字变小所得到的 m 值更小。

     我的错误代码

    #include "iostream"
    #include "math.h"
    #include "algorithm"
    #include "string.h"
    #define N 10000000;
    using namespace std;
    int top,list[120],MIN,m,n,flag,data[120][10];
    int count(){
     int i,num=0;
     //for(i=1;i<top;i++)cout<<list[i];cout<<endl;system("pause");
     for(i=1;i<top;i++){
       num+=data[i][list[i]];
     }
     return num;
    }
    int min(int a,int b){return a>b?b:a;}
    
    void dfs(int s,int num){
      int i,j;
      if(num==0){
        int ans=count();
        if(ans%m!=0)return;
        if(ans%m==0){flag=1;return;}
        //cout<<"*****"<<ans<<endl;system("pause");
      }
      for(i=s;i<=top-num;i++){
        if(i==top-1)j=1;
        else j=0;
        for(;j<=9;j++){
          int tem=list[i];
          list[i]=j;
          dfs(i+1,num-1);
          if(flag==1)
           return;
          list[i]=tem;
        }
      }
    }
    
    void make(){
      int i,j;
      data[0][1]=1;
      for(i=1;i<120;i++){
        data[i][1]=data[i-1][1]*10%m;
        for(j=2;j<10;j++){
          data[i][j]=data[i][1]*j%m;
        }
      }
    }
    
    int main(){
      int i;
      char s[120];
      while(cin>>s>>m){
        make();
        top=1;
        for(i=strlen(s)-1;i>=0;i--){
          list[top++]=(int)(s[i]-'0');
        }
        //for(i=1;i<top;i++)cout<<list[i];cout<<endl;system("pause");
        MIN=N;flag=0;
        for(i=1;i<top;i++){
          dfs(1,i);
          if(flag==1)break;
        }
        for(i=top-1;i>=1;i--)cout<<list[i];cout<<endl;
      }
    }

    大神的代码,附有一些解释

    #include <stdio.h>
    #include <string.h>
    #include <iostream>
    #include <math.h>
    
    const int N = 110;
    #define _clr(a,val) (memset(a,val,sizeof(a)))
    typedef long long ll;
    
    using namespace std;
    
    int mod[N][10];  
    int num[N],path[N];
    int rest[N][10010];  // rest[i][j] = k 表示搜索的区间是[0,i],当前串对 m 的取余为 j 时,剩余的允许改变的数字次数为 k
    char str[N];
    int kmod,len;
    void init()
    {
        int i,j;
        for(i = 0; i < 10; i++) mod[0][i] = i % kmod;
        for(i = 1; i < len; i++)
        {
            for(j = 0; j < 10; j++)
            mod[i][j] = ((10 % kmod) * (mod[i - 1][j] % kmod)) % kmod;  
        }
    }
    int dfs(int pnum,int s,int pmod)  // pnum:在区间 [0,s]内剩余允许改变的数字个数  s:当前搜索的区间[0,s]  pmod:当前数字串对 k 求模的值
    {
        //cout<<"pnum = "<<pnum<<" "<<s<<" "<<pmod<<endl;
        if(!pmod)
        {
            for(int i = len - 1; i >= 0; i--)  printf("%d",path[i]);
            printf("
    ");
            return 1;
        }
        int tmod;
        if(pnum == 0 || rest[pnum][pmod] > s) return 0;  // 剪枝  当前剩余的改变次数为零,或者在搜索的区间内,且当前对数字串m对 kmod 取余为 pmod时,剩余的修改(使得pmod == 0)数字次数 大于 区间时。直接返回
        for(int i = s; i >= 0; i--)  // 搜索比n小的数字,此时为了搜索到的解 m 是最小的,应该从区间[0,s]的第s位开始向第0位搜索,因为在相同 pnum 情况下,把高位数字变小所得到的 m 值更小。
        {
            for(int j = 0; j < num[i]; j++)
            {
                if(i == len - 1 && j == 0) continue;
                tmod = (pmod - (mod[i][num[i]] - mod[i][j]) + kmod) % kmod;  // 当把 m 的第i位数字 m[i] 改为j时,我们已经有((10^i)*m[i])%k的值存放在数组mod[i][m[i]]中,又有((10^i)*j)%k的值存放在数组mod[i][j]中,那么把m值改小前后的变化值为(mod[i][m[i]]- mod[i][j])
                path[i] = j;
                if(dfs(pnum - 1,i - 1,tmod)) return 1;
            }
            path[i] = num[i];
        }
        for(int i = 0; i <= s; i++)  // 搜索比 n 大的,应该从区间的开始搜索,这样能保证最小
        {
            for(int j = num[i] + 1; j < 10; j++)
            {
                if(i == len - 1 && j == 0) continue;
                tmod = (pmod + (mod[i][j] - mod[i][num[i]])) % kmod; 
                path[i] = j;
                if(dfs(pnum - 1,i - 1,tmod)) return 1; 
            }
            path[i] = num[i];
        }
        rest[pnum][pmod] = s + 1;
        return false;
    }
    int main()
    {
        int i;
        //freopen("data.txt","r",stdin);
        while(scanf("%s",str) != EOF)
        {
            len = strlen(str);
            scanf("%d",&kmod);
            init();
            _clr(rest,0);
            int tmod = 0;
            for(i = 0; i < len; i++)
            {
                num[i] = path[i] = (str[len - 1 - i] - '0'); 
                tmod = (tmod + mod[i][num[i]]) % kmod;
            }
            i = 0;
            while(1)
            {
                if(dfs(i++,len - 1,tmod)) break; 
            }
        }
        return 0;
    }
  • 相关阅读:
    045_分页查询插件 bootstrap_pagination
    Kali中文乱码问题
    将一行很长的js代码格式化输出方便查看
    使用gcc编译c语言解码ascii码
    Netcat
    阿里云万网注册个人域名并配置解析主机
    使用阿里云服务器配置frp实现Windows系统RDP内网穿透
    mysql数据库行级锁的使用(二)
    关于mysql数据库行级锁的使用(一)
    关于volatile的可见性问题
  • 原文地址:https://www.cnblogs.com/dowson/p/3349612.html
Copyright © 2020-2023  润新知