ACM PKU 1014 Dividing http://acm.pku.edu.cn/JudgeOnline/problem?id=1014
0-1背包 + 完全背包 + 滚动数组解题:
将完全背包进行二进制转换是第一次尝试;
0-1背包DP用得不熟悉,有待提高;
滚动数组不适应,以后应加强这方面的训练;
查找错误时,思维混乱,一个简单的初始化调了一个晚上都没找到,思维能力需要培养;
这是一个有价值的DP题目,代码展示一下,虽然不是0S A的;
#include <iostream> using namespace std; static int event = 1; int sign ; int num[7]; int sum = 0; int equ_val = 0; int dp[2][100002]; int store[20002]; bool charge () { if ((num[1]==0)&&(num[2]==0)&&(num[3]==0)&&(num[4]==0)&&(num[5]==0)&&(num[6]==0)) return false ; else return true; } void output0 () { cout << "Collection #"<<event<<":"<<endl; cout <<"Can't be divided."<<endl<<endl; } void output1() { cout << "Collection #"<<event<<":"<<endl; cout <<"Can be divided."<<endl<<endl; } void init () //初始化,将完全背包转化成0-1背包;利用的是二进制思想; { int j , k , a , temp; memset(store,0,sizeof (store)); sign = 0; for ( j = 1; j <=6 ; j++) { a = j * num[j]; for ( k = 1; k <=num[j] ; k++) { temp = j * k; if(a == 0) break; if (temp > a) { store[sign++] = a; break; } else store[sign++] = temp; a = a - temp; } } } bool solve () { memset (dp,0,sizeof (dp)); if (sum % 2 == 1) return false; equ_val = sum / 2; int i , j , k , Max = 6; dp[0][0] = 1; for(i = 0 ;i <= sign ; i++) //滚动数组和0-1背包结合,节省内存; { k = i; k %= 2; for(j = Max ; j >= 0; j--) { if(j + store[i] > equ_val) continue; dp[(k + 1) % 2][j + store[i]] = dp[k][j]; dp[(k + 1) % 2][j] = dp[k][j]; if(dp[(k + 1) % 2][j + store[i]] && j + store[i]> Max) Max = j + store[i]; if(dp[(k + 1) % 2][equ_val]) return true; } if(Max > sum / 2) Max = sum/2; } return false; } int main () { int i; while (1) { for(i = 1 ; i<= 6 ;i++) cin>>num[i]; if (!charge()) break; sum = 0; //开始时没有初始化,白忙活了一个晚上,该死!!! for (i = 1;i <= 6 ; i ++) sum += i * num[i]; init (); bool flag = solve(); if (flag == true ) { output1(); event++; } else { output0(); event++; } } return 0; }