pku 3373 Changing Digits 贪心的DP,注意DP方向

pku 3373 Changing Digits 贪心的DP,注意DP方向

题意:
给出2个整数N和K,求满足以下条件的整数M
1、M与N位数相同
2、M能被K整除
满足以上两点的情况下,与N不同位数的个数以及M值最小的优先
n<10^100
k<10000
解法:
考虑到k不大,状态可以设置为dp[i][k],即i位的数字中余数为k的需要修改的最小值
但是由于最后一个约束条件,即数小的优先,如果从正向DP,不能满足要求
应为从状态i-1转移到状态i的过程中,贪心的DP保证了第i位取值最小。可能出现这种状况:
假设abcd%k==efgh%k
d<h,但a>e。这样就不满足题意了。
解决方法是逆向DP,这样既能保证靠近前面的位取值最小。

代码:
 1 Source Code
 2
 3 Problem:  3373   User: yzhw 
 4 Memory: 12180K  Time: 1235MS 
 5 Language: G ++   Result: Accepted 
 6
 7 Source Code 
 8 # include  < cstdio >
 9 # include  < cstring >
10 using   namespace  std;
11 int  dp[ 105 ][ 10000 ];
12 int  path[ 105 ][ 10000 ][ 2 ];
13 void  print( int  start, int  left, int  len)
14 {
15   if(start>=len+1return;
16   printf("%d",path[start][left][1]);
17   print(start+1,path[start][left][0],len);
18}

19 int  main()
20 {
21    char str[105];
22    int mod[105];
23    while(scanf("%s",str+1)!=EOF)
24    {
25        int k;
26        scanf("%d",&k);
27        memset(dp,-1,sizeof(dp));
28        mod[strlen(str+1)]=1%k;
29        for(int i=strlen(str+1)-1;i>=1;i--)
30           mod[i]=(mod[i+1]*10)%k;
31        dp[strlen(str+1)+1][0]=0;
32        for(int i=strlen(str+1);i>0;i--)
33          for(int p=(i==1?1:0);p<10;p++)
34            for(int j=0;j<k;j++)
35             if(dp[i+1][j]!=-1)
36                    if(dp[i][(j+p*mod[i])%k]==-1||dp[i][(j+p*mod[i])%k]>dp[i+1][j]+(p!=str[i]-48))
37                    {
38                       dp[i][(j+p*mod[i])%k]=dp[i+1][j]+(p!=str[i]-48);
39                       path[i][(j+p*mod[i])%k][0]=j;
40                       path[i][(j+p*mod[i])%k][1]=p;
41                    }

42        print(1,0,strlen(str+1));        
43        printf("\n");
44    }

45    return 0;
46}

47
48
49

你可能感兴趣的:(pku 3373 Changing Digits 贪心的DP,注意DP方向)