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;
}