您的位置:首页 > 其它

POJ_3373_Changing Digits_DP

2015-05-05 23:18 190 查看
好想去游泳。


题意

一个不超过100位的数字n和一个不超10000的数字k,改变其中的一些数字(可以改变0个数字),得到一个新的数字m,满足下列条件:

长度和n相同,除0外无前缀0

m可以被k整除

m尽可能改变少的数字

3优先的情况下m尽可能小

IO

Input

There are multiple test cases for the input. Each test case consists of two lines, which contains n(1≤n≤10100) and k(1≤k≤104, k≤n) for each line. Both n and k will not contain leading zeros.

Output

Output one line for each test case containing the desired number m.

分析

做出来以后看了看题解,发现用搜索做的人还用了抽屉原理,然后推出来只需要改变5位就可以搜出来因此只搜最后五位。然而这道题条件的优先级是改变数量少优先于改变后数字小,因此并没有什么卵用。

我用的是DP+记录DP路径,这题的DP搜索顺序挺坑爹的。

dp[i][j]定义为到第i位,除k余数为j时需要改变的数量。

dp[i][j]=min(dp[i][j], dp[ii][jj]),遍历当前位的数字l来递推,ii,jj为另一个i, j编号

min操作使得递推肯定抱枕改变的位数最小。

由于需要使数值最小,高位数字需要更大权利,因此从后向前遍历i,每一层i选择当前数字l都从0到9遍历,余数最不重要放在最里层。i从后向前遍历的原因可以从终点那里看出来。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define MXL 110
#define MXK 10010
#define INF 0x3f3f3f3f
char a[MXL];
int k;
int dp[MXL][MXK];
int pre[MXL][MXK];
int rec[MXL][MXK];
char ans[MXL];
int anscur;
int main(){
while(scanf("%s%d",a,&k)!=EOF){
int len=strlen(a);
anscur=0;
memset(ans,0,sizeof(ans));
memset(dp,0x3f,sizeof(dp));
memset(pre,-1,sizeof(pre));
dp[len][0]=0;
int t=1;
for(int i=len;i>0;--i){
if(i!=len)  t*=10;
t%=k;
for(int l=0;l<10;++l)
for(int j=0;j<k;++j)    if(dp[i][j]!=INF){
if(len>1&&i==1&&l==0)   continue;
int tem=1-(l==a[i-1]-'0');
if(dp[i][j]+tem<dp[i-1][(j+l*t)%k]){
dp[i-1][(j+l*t)%k]=dp[i][j]+tem;
pre[i-1][(j+l*t)%k]=j;
rec[i-1][(j+l*t)%k]=l;
}
}
}
int nowl=0,nowj=0;
while(nowl<len){
ans[anscur++]=rec[nowl][nowj]+'0';
nowj=pre[nowl][nowj];++nowl;
}
printf("%s\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: