Partitions of a set
Post date: Nov 28, 2013 1:07:45 AM
در این پست برنامهای هست که تعداد افرازهای یه مجموعه n عضوی رو چاپ میکند. همه افرازهای مجموعه {1,2,3} اینها هستند:
{{1,2,3}}
{{1,2},{3}}
{{1,3},{2}}
{{1},{2,3}}
{{1},{2},{3}}
پس یک افراز برای مجموعه {1,2,3} همه دسته بندیهای اعضای آن است. دانستن یک نکته خیلی ضروری است. ترتیب، برای اعضایی که بین { و } قرار میگیرند مهم نیست. پس
{1,2} = {2,1}
و
{{1,3},{2}} = {{2},{1,3}} = {{2},{3,1}}
پس برنامه باید فقط یکی از این مجموعههای مساوی را چاپ کند.
افراز برای مجموعههای n عضوی شبیه مثال سه عضوی بالاست.
اگر با مفهوم مجموعه مشکل دارید، مسئله را میشود به شکل دیگری بیان کرد: فرض کنید n سکه با قطرهای مختلف داریم که روی میز از بزرگ به کوچک روی هم چیده شدهاند. این n سکه را به چند صورت میشود در دستههای چندتایی روی میز چید که سکه پایینی بزرگ تر از بالایی باشد:
در این شکل 5 حالت ممکن از چیدن سه سکه روی میز نشان داده شده است. میبینید که همه این حالتها متناظر با 5 افرازی است که در بالا نشان داده شده است.
حالا برنامهای که افرازهای یک مجموعه n عضوی را چاپ میکند:
#include
<conio.h>
#include
<iostream>
#include
<vector>
using
namespace
std;
template<typename
type>
class
Set
{
public://
vector<type>
v;
bool
Contains(type
element)
{
unsigned
size
=
v.size();
for(unsigned
i
=
0;
i
<
size;
i++)
{
if(element
==
v[i])
return
true;
}
return
false;
}
//-------------------------------------------
void
Empty()
{
v.clear();
}
//-------------------------------------------
void
NotMultiple()
{
for(unsigned
i
=
0;
i
<
v.size();
i++)
for(unsigned
j
=
i
+
1;
j
<
v.size();
j++)
{
if(v[i]
==
v[j])
{
v.erase(v.begin()
+
j);
j--;
}
}
}
//-------------------------------------------
void// Pop()
{
v.pop_back();
}
//-------------------------------------------
bool
Push(type
element)
{
if(!Contains(element))
{
v.push_back(element);
return
true;
}
return
false;
}
//-------------------------------------------
unsigned
Size()
{
return
v.size();
}
//-------------------------------------------
type&
operator
[](unsigned
i)
{
if(Size()
<=
i)
i
=
Size()
-
1;
return
v[i];
}
//-------------------------------------------
bool
operator
==
(Set<type>
set)
{
vector<type>
v1
=
v;
vector<type>
v2
=
set.v;
while(true)
{
if(v1.size()
==
0)
{
if(v2.size()
==
0)
return
true;
else
return
false;
}
bool
found
=
false;
for(unsigned
i
=
0;
i
<
v2.size();
i++)
{
if(v1[0]
==
v2[i])
{
v2.erase(v2.begin()
+
i);
found
=
true;
}
}
if(found
==
false)
return
false;
v1.erase(v1.begin());
}
return
true;
}
public:
Set(vector<type>
v)
:v(v)
{
NotMultiple();
}
//-------------------------------------------
Set()
{
}
};
class
Partitioner
{
vector<int>
set;
public:
Set<Set<Set<int>
>
>
SSS;
void
Print()
{
unsigned
size_sss
=
SSS.Size();
for(unsigned
k
=
0;
k
<
size_sss;
k++)
{
cout<<
"{";
unsigned
size_ss
=
SSS[k].Size();
for(unsigned
j
=
0;
j
<
size_ss;
j++)
{
cout<<
"{";
unsigned
size_s
=
SSS[k][j].Size();
for(unsigned
i
=
0;
i
<
size_s;
i++)
{
cout<<
SSS[k][j][i];
if(i
<
size_s
-
1)
cout<<
",";
}
cout<<
"}";
if(j
<
size_ss
-
1)
cout<<
",";
}
cout
<<
"}\n";
}
}
//------------------------------------------
void
Run()
{
unsigned
size
=
set.size();
unsigned
i
=
size
-
1;
/*
sweeper
item
can
be
any
number
between
0
&
size
-
1
*/
if(size
==
0)
return;
Set<Set<int>
>
SS;
Set<int>
S;
S.Push(set[i]);
SS.Push(S);
if(size
==
1)
{
SSS.Push(SS);
return;
}
vector<int>
subset;
for(unsigned
j
=
0;
j
<
size;
j++)
{
if(i
!=
j)
subset.push_back(set[j]);
}
Partitioner
P(subset);
unsigned
P_size
=
P.Size();
for(unsigned
k
=
0;
k
<
P_size;
k++)
{
unsigned
size_k
=
P[k].Size();
for(unsigned
j
=
0;
j
<=
size_k;
j++)
{
bool
change
=
P[k][j].Push(set[i]);
SSS.Push(P[k]);
if(change)
P[k][j].Pop();
}
bool
change
=
P[k].Push(S);
SSS.Push(P[k]);
if(change)
P[k].Pop();
}
}
//------------------------------------------
unsigned
Size()
{
return
SSS.Size();
}
//------------------------------------------
Set<Set<int>
>&
operator[](unsigned
i)
{
if(Size()
<=
i)
i
=
Size()
-
1;
return
SSS[i];
}
public:
Partitioner(vector<int>
set)
{
Set<int>
S(set);
this
->
set
=
S.v;
Run();
}
};
int
main()
{
vector<int>
v1;
v1.push_back(1);
v1.push_back(2);
v1.push_back(3);
v1.push_back(4);
//
v1
=
{1,2,3,4}
Partitioner
P(v1);
P.Print();
cout<<
P.Size();
_getch();
}
Output:
{{1,2,3,4}}
{{1,2,3},{4}}
{{1,2,4},{3}}
{{1,2},{3,4}}
{{1,2},{3},{4}}
{{1,3,4},{2}}
{{1,3},{2,4}}
{{1,3},{2},{4}}
{{1,4},{2,3}}
{{1},{2,3,4}}
{{1},{2,3},{4}}
{{1,4},{2},{3}}
{{1},{2,4},{3}}
{{1},{2},{3,4}}
{{1},{2},{3},{4}}
15
در این برنامه، کلاس Set یک مجموعه را شبیه سازی میکند با خاصیت مهمی که گفتم: ترتیب در مجموعه مهم نیست. تساویای که در کلاس Set تعریف شده مجموعههای مساوی را با توجه به عدم اهمیت ترتیب معین میکند. این تساوی مهم ترین علت نوشتن این کلاس است. البته میشد از کلاسهای استاندارد هم برای این کار استفاده کرد.
علت استفاده از
Set<Set<Set<int> > > SSS;
این است که مجموعه همه افرازها، یک مجموعه است؛ هر افراز هم مجموعه است و هر افراز شامل چند مجموعه است. پس سه دسته تو در تو از مجموعهها داریم.
این برنامه از بازگشت استفاده میکند و نوشتن برنامه بدون استفاده از بازگشت شاید کاری بسیار سخت و طاقت فرسا باشد. اما شاید همین مفهوم بازگشت را بشود با لیستها، بازسازی کرد به طوری که دیگر نشود اسمش را بازگشت گذاشت.