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 阅读(288) 评论(0) 编辑 收藏 举报