Министерство образования Российской Федерации
Государственное образовательное учреждение высшего
профессионального образования
«Комсомольский-на-Амуре Государственный Технический Университет»
Кафедра МОП ЭВМ
ЛАБОРАТОРНАЯ РАБОТА 2
Преподаватель: Изабеков З.А.
2004 г.
Задание:
Решить задачу с помощью алгоритма перебора с возвратом.
Вариант 8:
1. Задано множество A = {a1,a2,…an}, натуральные числа s(ai)>0, и k>0. Найти разбиение множества А на попарно непересекающиеся подмножества, при котором минимальна.
Решение:
Разбиением множества A={a1,a2,…,an} называется множество его подмножеств B1,B2,…,Bk таких, что BiÇBj=Æ для всех 1£i<j£k, и . Для перебора разбиений можно предполагать, что A={1,2,3,…,n}.
Наш метод будет основан на построении разбиений множества {1, 2,…, n}, исходя из разбиения множества {1, 2,…, n-1}. Если построено разбиение {B1, B2,…, Bk} множества {1, 2,…, n-1}, то легко найти следующие разбиения множества {1, 2,…, n}:
B1È{n}, B2,…, Bk,
B1, B2 È{n},…, Bk,
…
B1, B2,…, Bk È{n},
B1, B2,…, Bk,{n}.
такой подход позволяет генерировать все разбиения множества {1, 2,…, n}, исходя из всех разбиений множества {1, 2,…, n-1}.
Каждое разбиение множества {1,2,…, n} будем представлять как последовательность блоков, упорядоченных по возрастанию самого маленького элемента в блоке. Этот наименьший элемент блока мы будем называть номером блока. Для каждого элемента i, 1 £ i £ n, номер блока, содержащего элемент i, будем хранить в элементе block[i].
Разработаем рекурсивную подпрограмму, аргументом которой служит k>0, генерирующую из разбиения множества {1, 2,…, k-1} продолжающие его разбиения множества {1,2,…,k}. Опишем подпрограмму подробнее. Пусть получено разбиение множества {1, 2,…, k-1}, определенное с помощью массива block[1], …, block[k-1]. Тогда j пробегает элементы 1, 2, …, k-1, и, как только j попадет в некоторый блок, став равным наименьшему элементу этого блока block[j] = j, к этому блоку добавим элемент k с помощью операции block[k] = j. Получаем новое разбиение, которое в случае k = n выводиться на экран. В случае k<n вызывается функция rec(k+1). Кроме значений j = 1, 2,…, k-1 рассматривается j = k, в этом случае новый блок разбиения будет состоять из единственного элемента k. Приходим к следующему тексту программы:
Текст программы:
#include<stdio.h>
#include<conio.h>
#define n 4
int block[n+1];
int s[4]={1,2,3,4};
int temp;
void rec(int k)
{
int i,j,m,sum,sum1,priz=0;
for (i=0;i<n;i++) temp=s[i]+temp;
temp=temp*temp;
for(j=1;j<=k;j++)
{
if(block[j]==j) block[k]=j;
else if (j==k) block[k]=k; else continue;
if(k==n)
{
printf("\n");
sum=0; sum1=0;
for (i=1;i<=n;i++)
{
for(m=1;m<=n;m++)
{if (block[m]==i)
sum1=s[m-1]+sum1;
}
sum1=sum1*sum1;
sum=sum+sum1;
sum1=0;
}
if (sum<=temp)
{ clrscr();
printf("%d\n",sum);
temp=sum;
for (i=1;i<=n;i++)
{ priz=0;
for(m=1;m<=n;m++)
if (block[m]==i)
{if (priz==0) {printf("(");priz++;}
printf(" %d ",m);}
if (priz==1) printf(")");
}
}
}
if (k<n) rec(k+1);
}
}
void main()
{clrscr();
int i;
for (i=0; i<=n; i++) block[i]=0;
block[1]=1;
rec(2);
getch();
}
В результате мы получаем разбиения множества {1, 2, 3, 4}:
( 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 )
Но из всех выберется только то разбиение, для которого минимальна.
Результат работы программы:
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.