partition is a decision problem which was defined as following:
instance: a set A = {a1, a2, .., an} of n nonegative integers.
question: is there a subset B such that the sum of B is equal to A-B?
the brute-force algorithm that tries every prossibles subset consumes no less than 2exp(n) time.
the dynamic programming for partition problem uses O(n*sum) time.
the recurrence relation
if sum odd, reply "no", and done;
let table(i, j) denote the truth value of the statement
"there is a subset of (a1, a2, .. , aj} for which the sum of integers is exactly j", where 1<= i <= n and 0 <= j <= sum/2;
we are asked to compute table(n, sum/2)
we derive:
the general recurrence table(i, j) = t(i-1, j) U table(i-1, j-ai),with the base value:
1. table(i, j) = 1, if j==0;
2. table(i, j) = 1, if i==1 and j = a1;
3. table(i, j) = 0, 0<j!=a1 and i = 1;
then we use the base value to computer the following value ,when we fill the table,the last value indicate there is a subset satisfy the condition or not.
the c++ code write for this question as following.
the header file:
#pragma once
#ifndef _SUBSET_H
#define _SEBSET_H
typedef struct _SetDesc
{
public:
unsigned int *pUintSet;
unsigned int setCount;
}SSetDesc;
class subSet
{
private:
//
//set description
SSetDesc m_set;
//
//set for result
SSetDesc m_subSet;
public:
subSet(void);
subSet(unsigned int *uintSet, unsigned int setCount);
subSet(SSetDesc uintSet);
//
//if the return value is NULL, it indicate there is not a subset in accordance with you require
SSetDesc * result( );
~subSet(void);
};
#endif
the implement code:
#include "StdAfx.h"
#include "subSet.h"
subSet::subSet( void )
{
}
subSet::subSet( unsigned int *uintSet, unsigned int setCount )
{
if( uintSet )
{
m_set.pUintSet = new unsigned int[ setCount ];
memcpy( m_set.pUintSet, uintSet, setCount*sizeof( unsigned int ) );
m_set.setCount = setCount;
}
printf( "there are %d elements:/n", m_set.setCount );
for( unsigned int i = 0; i < setCount; ++i )
{
printf( "%d/t", *( m_set.pUintSet + i ) );
}
printf("/n");
}
subSet::subSet( SSetDesc uintSet )
{
if( uintSet.pUintSet )
{
m_set.pUintSet = new unsigned int[ uintSet.setCount ];
memcpy( m_set.pUintSet, uintSet.pUintSet, uintSet.setCount*sizeof(unsigned int) );
m_set.setCount = uintSet.setCount;
}
}
SSetDesc * subSet::result( )
{
//
//此处为算法实现部分
unsigned int sum = 0;
for(unsigned i = 0; i < m_set.setCount; ++i)
{
sum += *( m_set.pUintSet + i );
}
//
//如果和为奇数,则不存在, pass
if( 1 == sum%2 )
{
return NULL;
}
//
//构建一个虚拟化二维数组
unsigned int *table = new unsigned int[ m_set.setCount*( 1 + sum/2 ) ];
memset( ( void * )table, 0, m_set.setCount*( 1 + sum/2 )*sizeof( unsigned int ) );
printf("打印每一行/n");
for( int i = 0; i<m_set.setCount; ++i )
{
printf("/n");
for( int j=0; j<sum/2+1; ++j )
{
printf("%d/t", *(table + i*(1 + sum/2) + j) );
}
}
printf("/n");
//置表格第一列为1
for( unsigned int i = 0; i < m_set.setCount; ++i )
{
*( table + i*( 1+ sum/2 ) ) = 1;
}
//置表格第一行中列序号==第一个元素值的表格单元 1
for( unsigned int i = 0; i < ( 1 + sum/2 ); ++i )
{
if( i == *( m_set.pUintSet ) )
*( table + i ) = 1;
}
//
//
//table[ i ][ j ] = table[ i-1 ][ j ] U table[ i-1 ][ j-a
//table[ i-1 ][ j-a ] == 1意味着在不加入元素a[ i ]的情况下存在
//满足条件的集合
//
for( unsigned int i = 1; i < m_set.setCount; ++i )
{
for( unsigned int j = 0; j < 1 + sum/2; ++j )
{
//若某一元素为1,则表格中它下面的所有元素都为1
if( 1 == *( table + ( i - 1 )*( 1 + sum/2 ) + j ) )
{
*( table + i*( 1 + sum/2 ) + j ) = 1;
continue;
}
//
// *( table + ( i - 1 )*( 1 + sum/2 ) + j - *( m_set.pUintSet + i ) )
// 保证数组中列序号不为负
// 晕,在这里出错,MS编译器有一个小bug,if(无符数相减如果为负)
// if( ( j - *( m_set.pUintSet + i ) ) >= 0 )会出错,因为都是无符号数
// 相减为负时会溢出
//
if( j >= *( m_set.pUintSet + i ) )
{
if( 1 == *( table + ( i - 1 )*( 1 + sum/2 ) + j - *( m_set.pUintSet + i ) ) )
{
*( table + i*( 1 + sum/2 ) + j ) = 1;
}
}
}
}
//
//最后一个元素为1,则存在这样的集合m_set.setCount*( 1 + sum/2 )
if( 1 == *( table + m_set.setCount*( sum/2 +1 ) - 1 ) )
{
unsigned int i = m_set.setCount - 1;
//给j赋初值
unsigned int j = sum/2;
printf("/n打印出子集:/n");
while( i >= 0 && 1 == *( table + i*( sum/2 +1 ) + j ) )
{
if( 1 == *( table + ( i - 1 )*( sum/2 +1 ) + j ) )
{
//
//如果它上面的元素也为1,向上回溯
--i;
}
else
{
if( j != 0 )
printf("%d/t", *( m_set.pUintSet + i ) );
j = j - *( m_set.pUintSet + i );
--i;
}
}
}
/*for( unsigned int i = m_set.setCount - 1 ; i >= 0; --i )
{
for( unsigned int j = sum/2; j >= 0; --j)
{
}
}*/
printf("/n打印最后表格/n");
for( int i = 0; i<m_set.setCount; ++i )
{
printf("/n");
for( int j=0; j<sum/2+1; ++j )
{
printf("%d ", *(table + i*(1 + sum/2) + j) );
}
}
if( 1 == *( table + ( m_set.setCount - 1)*( 1 + sum/2 ) + sum/2 ) )
printf( "/nthere is a subset satisfy the condition" );
else
delete table;
return NULL;
}
subSet::~subSet( void )
{
}
dynamic programming resolve the partition problem
最新推荐文章于 2022-12-01 09:30:31 发布
dynamic programming resolve the partition problem