您的位置:首页 > 其它

poj3373--Changing Digits(DFS+剪枝///记忆化)

2017-09-20 17:54 375 查看
题目链接:点击打开链接

题目大意:给出一个n和一个k 求m

要求1、m要和n相同的位数

要求2、m要整除k

要求3、如果1和2满足,那么m要和n有尽量少的不同位

要求4、如果1、2、3满足,要使m尽量的小

简单的一个深搜,但是直接被要求吓蒙,,,,,

要求1和2直接可以在搜索时判断,要求3可以在深搜时给出可以改变的位数(有0到len(n)),而要求4需要控制在搜索是要从小的开始搜,即从100000到999999,因为在深搜之前就控制了可以改变的次数,所以在搜索时不用担心要求3,只要使要求1要求2满足就可以,那么搜到的第一个就是最小的。

注意剪枝:

1、在每一次变化后都要直接计算出余数,当余数为0时,返回1,而不是一定要搜到最后一位。

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

2、flag[i][j]当搜到第i位余数为j时,没有找到结果的(修改位数),当以后遇到修改位数<=flag[i][j]时直接返回0。

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

char str[110];
int k,len,a[110];
int mod[110][10];
int flag[110][11000];
void init(){
for(int j=0;j<10;j++)
mod[0][j]=j%k;
for(int i=1;i<110;i++)
for(int j=0;j<10;j++)
mod[i][j]=mod[i-1][j]*10%k;
}

int dfs(int num,int pos,int s){
if(s == 0) return 1;
if(num == 0 || pos == -1) return 0;
if(num <= flag[pos][s]) return 0;
int temp ;
for(int i=0;i<=9;i++){
if(pos == len-1 && i == 0 ) continue;
if(i<a[pos]){
temp=a[pos]-i;
a[pos]=i;
if(dfs(num-1,pos-1,(s-mod[pos][temp]+k)%k)) return 1;
a[pos]+=temp;
}
else if(i == a[pos]){
if(dfs(num,pos-1,s)) return 1;
}
else{
temp=i-a[pos];
a[pos]=i;
if(dfs(num-1,pos-1,(s+mod[pos][temp])%k)) return 1;
a[pos]-=temp;
}
}
flag[pos][s]=max(flag[pos][s],num);
return 0;
}

int main(){
int i,j,s,temp;
while(scanf("%s %d",str,&k)!=EOF){
memset(flag,-1,sizeof(flag));
len=strlen(str);
for(i=len-1;i>=0;i--){
a[len-1-i]=str[i]-'0' ;
}
init();
for(i=s=temp=0;i<len;i++){
s=(mod[i][a[i]]+temp)%k ;
temp=s;
}
for(i=0;i<=len;i++){
if(dfs(i,len-1,s)) break;
}
for(i=len-1;i>=0;i--)
printf("%d",a[i]);
printf("\n");
}
return 0;
}

/*
535064
9084
535956

19169 15724
15724

3902 153
3978
*/


代码快来拿
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: