Reprinted please indicate the source: Thank you http://blog.csdn.net/lyy289065406/article/details/6698787
General question:
Returns two integers n (n <10 ^ 100) and K (k <10000), and returns an integer m that meets the following conditions:
1. M and N digits are the same
2. m can be divisible by K
3. When the preceding two points are met, m and n are in the same position, and the numbers are the least.
4. When the above three points are met, the m value is the minimum.
Solution:
There are many solutions to this problem. Some use DP, some use memory-based search, and some use search + strong pruning.
Poj categories classify this question into "memory-based search", but I do not recommend it because it is not easy to directly write a memory-based search algorithm to solve the problem, instead of using DP, memory-based search is hard to implement.
I usedDFS + strong pruning.
I didn't have any idea when I was doing this. I wanted to refer to the practices of my predecessors on the Internet, but it was basically a mess of things, I will explain the clear problem-solving process based on my own ideas. This idea draws on others' practices, but it is definitely clearer than him.
Enter the subject below:
1. solution of the problem
Let n % K = n_modk, according to the drawer principle, in [0, k-1] The K sequence natural number, there must be a number and n_modk is the same class. According to the question k <= N, it indicates that this question must be answered.
However, this only proves that DFS can find a solution, but it cannot help solve the problem.
I don't know which one is so wicked. I spread a rumor on the Internet that "because K has only five digits at most, we only need to change n's last five digits to find the answer according to the drawer principle ".
This is absolutely wrong. This is because Condition 4 cannot be met.
Because of this, some people may search for the last Len (k) bit of N to save time when doing this, but they do not know why. This method is wrong: when you change the value of one of the N Low numbers to a smaller value, the n_modk = 0, however, if you change the value of one of the N high numbers to the same value as that of n_modk = 0, the latter must be obtained to satisfy Condition 4, the principle of the drawer "as long as the last five digits of N are changed" cannot meet this condition.
The correct statement should be "a maximum of five digits in N can be solved", but it is not necessary to apply the drawer principle in actual problem solving. Because the first solution searched by DFS must be optimal, therefore, allownum can be enumerated one by one from one to Len (n), which can avoid discussing whether Len (n) is greater than 5.
2. Order of solutions
First, you must note that the conditions for this question are hierarchical. Condition 1 takes precedence over condition 2, condition 2 takes precedence over Condition 3, and Condition 3 takes precedence over condition 4 ,. Because of the large data volume, to save search time, we must ensure that the first answer to the DFS search is optimal. Therefore, this sets the DFS search direction.
3. High-precision processing
N has a maximum of 101 digits. In the past, the n_modk method used the same modulus formula to calculate the modulus from the high position to the low position, A slightly changed method is used to calculate n_modk.
Store N in reverse order.
Define the array mod [101] [10], MOD [I] [J] = (10 ^ I) * j) % K, first find:
0 1 2 3 4 5 6 7 8 9 (% K)
0 10 20 30 40 50 60 70 80 90 (% K)
0 100 200 300 400 500 600 700 800 900 (% K)
.....
By using the recursive mod [I] [J] = (mod [I-1] [J] * 10) % K;, we can avoid the N power operation and save time.
Then mod [] [] can combine the values after modulo K for the integer in the meaning Len (n) bit. The n_modk can be obtained using the same modulus formula.
4. DFS Search Method
Bool DFS (INT POs, int restnum, int m_modk );
There are three input parameters: POs, restnum, and m_modk.
POs: the current search interval is [0, POS]
Restnum, N and M have the least numbers at the same position (Condition 3 ).
M_modk: The modulo value of the current numeric string M, initialized to n_modk.
Portal processing:
For (INT allownum = 1; allownum <= Len; allownum ++)
If (DFS (len-1, allownum, n_modk ))
Break;
Each entry has a Pos = len-1, is to ensure that the largest search area.
(1) Search for numbers smaller than N before searching. In this case, in order to find the smallest solution m, we should start to search for 0th digits from the POs position in the range [0, POS, in the case of the same restnum value, the m value obtained when the high number is reduced is smaller.
(2) When (1) there is no solution, search for numbers greater than n. In this case, in order to find the minimum solution m, the range [0, pos] 0th bits start to search for the POs bits, because in the same restnum case, the m value obtained by increasing the low number is smaller.
Export processing:
M_modk = 0 returns true
Returns false if restnum is set to 0.
5,Transmission of the third parameter value m_modk:
Since the number string M changes with the search depth, it is a waste of time to re-find m_modk Based on the n_modk method after each change. In this case, we need to use the same modulus formula and mod array.
The same modulus formula used to search for numbers smaller than N is:
(A-B) % K = (a % K-B % K) % K
The same modulus formula used to search for numbers greater than N is:
(A + B) % K = (a % K + B % K) % K
(1) When searching for numbers smaller than N, we already have (10 ^ I) * m [I]) % K values are stored in the array mod [I] [M [I], and (10 ^ I) * j) the value of % K is stored in the array mod [I] [J, change the m value to (mod [I] [M [I]-mod [I] [J]), then we know that M changes the modulo K value before m_modk. Then, we only need to subtract the m_modk before m changes (mod [I] [M [I]-mod [I] [J]) and then modulo K, is the new m_modk value. We make it equal to res.
To avoid negative numbers due to m_modk <(mod [I] [M [I]-mod [I] [J]), we should add a "+ k" correction process, the specific formula is as follows:
Res = (m_modk-(mod [I] [M [I]-mod [I] [J]) + k) % K;
Taking the number 5234, K = 25 as an example, In this algorithm, the array m is actually stored as the inverted Order of the number 4321, and the first is the 0th-bit "4 ", similarly, MOD [] [] Stores inverted data.
Data storage: M [] = 4325, K = 27
M_modk = 5234% 27 = 22 is known. Now we need to change the "5" of M's 3rd bits to a smaller "1", M [3] = 5, set j = 1, that is, M [3] = J. The actual change value after the change is 5000-1000 = 4000.
What we need now is the value of 1234% 27 after M is changed, while 1234% 25 = (5234% 27-4000% 27) % 27. Because 5234% 27 = m_modk = 22 is known, only 4000% 27 is required.
While 4000% 27 = (5000% 27-1000% 27) % 27, apparently 5000% 27 and 1000% 27 are saved in mod. 5000% 27 = mod [3] [M [3], 1000% 27 = mod [3] [J]. I should understand it here.
(2) When searching for numbers greater than N, the principle is similar, except that the direction of the change value subtraction changes. And because it is m_modk + change value, that is, there will be no negative number, so no "+ k" correction is required. The specific formula is as follows:
Res = (m_modk + (mod [I] [J]-mod [I] [M [I]) % K;
6. pruning:
Define a two-dimensional array int ** flag
Flag [POS] [m_modk] = restnum
When the position range of M is [0, POS], and the modulo value of M on K is m_modk,
If only the number of allowed numbers can be modified,
No matter how you modify the number in the range [0, POS], m_modk = 0,
For the same POs and m_modk, it is more impossible to have a number smaller than restnum.
// Memory time // 21444 K 47 Ms # include <iostream> # include <string> using namespace STD; Class solve {public: Solve (char * sn, int tk) {Len = strlen (SN); k = TK; n_modk = 0; initialflag (Len, k); playtable_mod (); calculation_n_modk (SN); For (INT allownum = 1; allownum <= Len; allownum ++) // enumerate the number of numbers that can be modified if (DFS (len-1, allownum, n_modk) // ensure the maximum break between search zones ;}~ Solve () {for (INT I = len-1; I> = 0; I --) cout <m [I]; cout <Endl; Delete [] flag ;} void initialflag (INT Len, int K); void playtable_mod (void); // create a table mod [] [], using the same modulus formula void calculation_n_modk (char * Sn ); // calculate n % kbool DFS (INT POs, int restnum, int m_modk); protected: int Len; int N [101], M [101]; int K; int n_modk; // n % Kint mod [101] [10]; // mod [I] [J] = (10 ^ I) * j) % Kint ** flag; // flag [POS] [m_modk] = restnum};/* When the position range of M is [0, POS], when the modulo value of M on K of the current numeric string is m_modk, if the number of allowed numbers to be modified is only allowed to be modified restnum, the interval [0, the number in the POs] cannot make m_modk = 0, so for the same POs and m_modk, less than the number of restnum is more impossible, which is used for pruning */void solve :: initialflag (INT Len, int K) {flag = new int * [Len + 1]; for (INT I = 0; I <= Len; I ++) {flag [I] = new int [k]; memset (flag [I], false, sizeof (INT) * k);} return;} void solve :: playtable_mod (void) {for (Int J = 0; j <= 9; j ++) mod [0] [J] = J % K; For (INT I = 1; I <Len; I ++) for (Int J = 0; j <= 9; j ++) moD [I] [J] = (mod [I-1] [J] * 10) % K; return;} void solve: calculation_n_modk (char * Sn) {for (INT I = 0; I <Len; I ++) {n [I] = m [I] = Sn [len-i-1]-'0 '; // returns N in reverse order and converts it to n_modk = (n_modk + mod [I] [n [I]) % K; // n % k} return;} bool solve:: DFS (INT POs, int restnum, int m_modk) {If (m_modk = 0) return true; If (restnum = 0 | POS <0) return false; if (restnum <= Flag [POS] [m_modk]) // pruning return false; int I, j; for (I = Pos; I> = 0; I --) // If the enumerated value is m smaller than N and M is as small as possible, for (j = 0; j <n [I]; j ++) starts from the high position) {if (I = len-1 & J = 0) // The maximum bit of M is not 0 continue; int res = (m_modk-(mod [I] [M [I]-mod [I] [J]) + k) % K; int TMP = m [I]; M [I] = J; // The I-1 is the reduction of the search area if (DFS (I-1, RestNum-1, Res) return true; m [I] = TMP ;} for (I = 0; I <= Pos; I ++) // enumerative number M larger than N, but m should be as small as possible, then for (j = N [I] + 1; j <= 9; j ++) {if (I = len-1 & J = 0) // The maximum M bit is not 0 continue; int res = (m_modk + (mod [I] [J]-mod [I] [M [I]) % K; // same modulus formula int TMP = m [I]; m [I] = J; // The I-1 is used to contract the search area if (DFS (I-1, RestNum-1, Res )) return true; m [I] = TMP;} flag [POS] [m_modk] = restnum; // In the interval [0, only the number of restnum can be modified in POS]. m_modk = 0 return false;} int main (void) {char Sn [101]; int TK; while (CIN> Sn> tk) Solve poj3373 (Sn, TK); Return 0 ;}