poj 3373记忆化搜索

题意:

给你一个n和k,要求找出m,满足以下条件

1.m的长度和n一样长

2.m % k == 0

3.满足1,2条件,m和n的不同位数要尽量少。

4.满足1,2,3条件,m要最小

难点:

1.n的为位数高达100位,如何处理高精度?如何解决m %k == 0

方法:同余取模

a + b = a % m + b % m

a * b = (a %m) * (b%m)

定义:

int mod[110][110];

mod[i][j] = [(10 ^ i ) * j] % k

mod[i][j] = (mod[i-1][j] * 10) % k

2.如何满足条件

注意搜索的次序性。次数从0到len-1次开始搜索,先搜索小的数,再搜索大的数

 

3. dfs

传递的参数有dfs(num,start,end,M)

num为改变数字的次数, 【start,end]为搜索区间,M为取模k后余数

4.直接搜索会TLE。。

需要记忆化搜索。。

dp[num][m] = c 表示搜索次数为num,余数为m,在区间(0,c-1)得不到解。

View Code
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<iostream>
using namespace std;

char str[1000];
int MOD[110][110];//MOD[i][j] = ((10^i) * j)%k,同余求模公式;
int n,k,len;
int dp[110][11110];

/*
满足的条件决定了搜索的次序:
1. 与n位数一样长 
2. 能整除k
3. 位数与n尽量相同
4. 满足1,2,3条件,且改数是最小的

剪枝
dp[i][j] = c 表示 剩余替换次数为i,当前余数为j时,index 在区间[0,c-1]时都不成立。 
*/
 
void init( )
{
  for( int i = 0; i <= 9; i++)
  {
     MOD[0][i] = i % k;     
       
  }
  for( int i = 1; i <= len; i++)
  {
     for( int j = 0; j <= 9; j++)
          MOD[i][j] = (MOD[i-1][j] * 10 ) % k ;
          
  }        
}

bool DFS(int s, int pos, int length, int M)
{  
   if( M == 0 )
   {
      for( int i = 0; i < len; i++)
           printf("%c",str[i]);
      puts("");
      return true;
   }
   if( s == 0 || dp[s][M] )
       return false;
   //先搜索比n小的数 
   for( int x = pos; x <= length; x++)
   {
        for( int i = 0; i < str[x]-'0'; i++)  //从0向str[x]搜索,保证最小 
        {
         if( x == 0 && i == 0 ) //第一个数不能为0 
             continue;
         int temp =  M - MOD[len - 1 - x][str[x] - '0'] + MOD[len-1-x][i];
         if( temp <  0 )
            temp += k;
         temp %= k;
         char c = str[x];
         str[x] = i + 48;
         if( DFS(s - 1, pos + 1, length, temp ) )
             return true;
         str[x] = c;
        }   
   }
   //再搜索比n大的数  
   for( int x = length; x >= pos; x--)
   {
       for( int i = str[x] - '0' + 1; i <= 9; i++)
       {
          if( x == 0 && i == 0 )
              continue;
          int temp =  M - MOD[len - 1 - x][str[x] - '0'] + MOD[len-1-x][i];
          if( temp <  0 )
            temp += k;
          temp %= k;
          char c = str[x];
          str[x] = i + 48;
          if( DFS(s - 1, pos, length - 1, temp) )
              return true;
          str[x] = c;     
       }
            
   }
   //如果没有搜索到,标记
   dp[s][M] = length + 1;   //当次数为j,余数为M的时候,在区间(0,length)都没解 
   return false;      
}

int main( )
{
  while( scanf("%s%d",str,&k) != EOF)
  {  
     len = strlen(str);
     init( );
     int sum = 0;
     int j = 0;
     for( int i = len-1; i >= 0; i--)
     {
        int x = str[i] - '0';
        sum += MOD[j][x];
        sum %= k;
        j++;
     }
     memset(dp, 0, sizeof(dp)); 
     for( int i = 0; i < len; i++)
     {
        if( DFS(i, 0, len - 1, sum) )
            break;
     }
         
  }
  return 0;
}

posted on 2012-07-26 18:25  more think, more gains  阅读(287)  评论(0编辑  收藏  举报

导航