Proof: poj 1014 modulus optimization pruning, partial recursion error, poj1014
After doing this question, I found that even if a question is feasible, it is not correct. Most of the questions are too weak.
Poj 1014 Dividing
There are 6 piles of stones with a weight of 1 2 3 4 5 6 respectively. You need to enter the number of each heap and check whether the stones can be evenly divided to make the values of the two piles the same.
There are two methods for this question on the Internet, including the wrong version, but it can also be AC. At first, this made me feel that the code was concise, but I could not prove it.
Next we will prove the error of the two methods.
1. Multiple backpacks
#include <map>#include<string>#include <iostream>#include<stack>#include<algorithm>#include <math.h>using namespace std;#define MAXN 100+60000int v[MAXN];int a[MAXN/3];int b[7] = {1, 60, 30, 20, 15, 12, 10};int N,T,n,sum;/*int direct[4][2]={-1,0,1,0,0,-1,0,1}; int dp[210][210][210];*/int max(int a,int b){return a>b?a:b;}int main(){int i,j,k,flag,casenum;casenum=0;while(1){casenum++;memset(v,0,sizeof(v));flag=0;sum=0;n=0;for(i=0;i<6;i++){scanf("%d",&k);if(k)flag=1;k=k%b[i+1];sum+=k*(i+1);for(j=1;j<=k;j++)a[n++]=i+1;}if(flag==0)break;if(sum&1){printf("Collection #%d:\nCan't be divided.\n\n",casenum);continue;}flag=0;sum/=2;v[0]=1;for(i=0;i<n;i++){for(j=sum;j>=a[i];j--){v[j]+= v[j-a[i]];if(v[sum]){flag=1;break;}if(flag)break;}}if(flag)printf("Collection #%d:\nCan be divided.\n\n",casenum);elseprintf("Collection #%d:\nCan't be divided.\n\n",casenum);}return 0;}
The Status defines several methods that can be transferred here.
K = k % B [I + 1];
This is a kind of optimization. At first, I thought it was amazing, but I didn't understand why I could do it.
It turns out to be wrong. The proof is as follows:
The modulo optimization is incorrect. The following shows how many optimizations are made.
1.1a + 2b + 3c + 4d + 5e + 6f
2.60 * m * t + 1a + 2b + 3c + 4d + 5e + 6f (t indicates the number of stones in a pile, and m indicates the weight of a rock in a pile)
Proving that the optimization is correct proves that 1 is a necessary condition
When 1 is set up, it naturally gets 2 sets up (60 can be divided into two heaps)
When 2 is true,
In the first case, the two parts can be divided, and the one part can be divided, so 60 * m * t is enough to be split.
In the second case, the two parts can be divided, and the one part cannot be divided. It is feasible to split the 60 * m * t part into two talents.
This proves that it is not feasible to split a certain heap, but it is not ruled out that every heap optimization will happen to be feasible.
The last example is for you.
1. 0 0 0 0 66 5-> 0 0 0 6 5 ture
2. 60 0 0 0 0 1-> 0 0 0 0 1 fault
To optimize it, use the binary method (, 4 ,..., 2 ^ (k-1), n [I]-2 ^ k + 1, and k is the maximum integer that satisfies n [I]-2 ^ k + 1> 0. For example, if n [I] is 13, the item is divided into four items with a coefficient of 1, 2, 4, and 6)
- Why are some transfer equations on the Internet v [I] [j] = max (v [I-1] [j], v [j-a [I] + a [I])?
- A: We can see that j-a [I] indicates the complementary status with a [I]. In fact, it is j. From all J perspectives, it has not changed, this is v [0] = 0
2. dfs version (reproduced on Daniel's Blog)
// Memory Time // 452 K 0 MS/* DFS */# include <iostream> using namespace std; int n [7]; // The number of items with the value of I int SumValue; // The total value of the item int HalfValue; // The value of bool flag; // indicates whether the value of SumValuevoid DFS (int value, int pre) {if (flag) return; if (value = HalfValue) {flag = true; return ;}for (int I = pre; I >= 1; I --) {if (n [I]) {if (value + I <= HalfValue) {n [I] --; DFS (value + I, I); if (flag) break ;}}return;} int main (int I) {int test = 1; while (cin> n [1]> n [2]> n [3]> n [4]> n [5]> n [6]) {SumValue = 0; // total item value for (I = 1; I <= 6; I ++) SumValue + = I * n [I]; if (SumValue = 0) break; if (SumValue % 2) // sum is an odd number, and {cout <"Collection #" <test ++ <': '<endl; cout <"Can't be divided. "<endl; // note that the empty row continue;} HalfValue = SumValue/2; flag = false; DFS (0, 6); if (flag) {cout <"Collection #" <test ++ <':' <endl; cout <"Can be divided. "<endl; continue;} else {cout <" Collection # "<test ++ <':' <endl; cout <"Can't be divided. "<endl; continue;} return 0 ;}
This version of dfs is well written, and this depth has two advantages worth considering.
1. Why n [I] is not directly subtracted from backtracking?
A: If you choose between two people, you must divide this part into two parts. If you do not select the nearest number, the remaining parts will be closer.
2. from big to small?
A: There may be multiple small ones that can be replaced directly with a large number.
Certificate ----------------------------------------------------------------------------------------------------------------------------------
But there is a problem.
In essence, the greedy strategy is used, but it cannot meet the requirements of some "jumps ".
Eg: 0 0 3 0 3 1 the numbers to be selected are not consecutive. In fact, there must be backtracking.
This version can be used to avoid this problem.
void divide(int cur_value, int cur_index) { // set break point if (flag) return; if (cur_value == half_value) { flag = true; return; } if (cur_value > half_value || cur_index >= max_index) return; divide(cur_value+array[cur_index], cur_index+1); divide(cur_value, cur_index+1); }
It seems that you should be cautious when learning