Permutacje bez powtórzeń

0

Witam
mam do napisania program, który generuje permutacje. Dla problemu znajdowania wszystkich permutacji znalazłem algorytm. Natomiast nie wiem, jak usunąć powtarzające się permutacje
np dla zbioru (1,1,3) program powinien wypisywać na wyjśce: (1,1,3), (1,3,1), (3,1,1). Algorytm generuje natomiast wszystkie powtarzające się permutacje. Nie wiem jak zmienić kod, tak aby nie pojawiały się powtarzające się permutacje.
Poniżej kod:

#include "stdafx.h"
#include <stdio.h>

void swap(int *a, int *b)
{
	int temp;
	temp = *a;
	*a = *b;
	*b = temp;
}

void print(int tab[], int size)
{
	for (int i = 0; i < size; i++)
		printf("%d ",tab[i]);
}



void perm(int tab[], int size)
{
	if (size == 1)
	{
		print(tab, 3);
		printf("\n");
	}
	else
	{
		for (int i = 0; i < size; i++)
		{
			swap(&tab[i], &tab[size - 1]);
			perm(tab, size - 1);
			swap(&tab[i],&tab[size-1]);
		}
	}
}

int main()
{
	int tab[3] = { 1,2,3 };
	perm(tab, 3);
    return 0;
}
1

Musisz użyć innego algorytmu. Ten działa poprawnie, generuje wszystkie permutacje, ale wejście jest złe, bo ewidentnie zakłada, że elementy się nie powtarzają.
Zresztą, bez powtórzeń znaczy, że elementy są unikalne. Dla zbioru 3 elementowego ilość kombinacji bez powtórzeń to 3! ... Wiec chyba nie tego szukasz... Nie pomyliłeś przypadkiem terminologi?

Wydaje mi się, że interesują Cię permutacje z powtórzeniami. Dla [1, 1, 3] masz 3! / 2! takich możliwości, co odpowiada temu co pokazałeś jako wyjście.

1

Tam w dokumentacji std::next_permutation jest implementacja, wystarczy przepisać do C:

int _next_permutation(int array [], int begin, int end) 
{
	if (begin == end)
		 return 0;
    int i = end;
    if (begin == --i) 
    	return 0;
    while (1) 
    {
    	int run1, run2;
    	run1 = i;
    	if (array[--i] < array[run1])
    	{
    		run2 = end;
    		while (!(array[i] < array[--run2]))
    			;
    		swap(array, i, run2);
    		reverse_array_in_range(array, run1, end);
    		return 1;
    	}
    	if (i == begin)
    	{
    		reverse_array_in_range(array, begin, end);
    		return 0;
    	}
    }
}

void swap(int array[], int left, int right)
{
    int temp;
    temp = array[left];
    array[left] = array[right];
    array[right] = temp;
}

void reverse_array_in_range(int arr[], int begin, int end)
{
	for (int i = begin; i <= end / 2; ++i) 
	{	
		int tmp = arr[i];
		arr[i] = arr[end - i];
		arr[end - i] = tmp;
	}
}
1

Ten algorytm jest dość skomplikowany:
https://arxiv.org/ftp/arxiv/papers/1503/1503.00067.pdf
Tu implementacja w Pythongu:
https://stackoverflow.com/questions/19676109/how-to-generate-all-the-permutations-of-a-multiset
Ten sam efekt osiągniesz, generując wszystkie permutacje i odsiewając duplikaty. POC w Pythonie:

from itertools import permutations

example = [1, 1, 3]

example_permutations = list(permutations(example))

print(example_permutations) # -> [(1, 1, 3), (1, 3, 1), (1, 1, 3), (1, 3, 1), (3, 1, 1), (3, 1, 1)]

unique_permutations = set(example_permutations) # creates set = removes duplicates

print(unique_permutations) # -> {(1, 1, 3), (1, 3, 1), (3, 1, 1)}

example_wiki = "babka" # https://pl.wikipedia.org/wiki/Permutacja#Permutacja_z_powt%C3%B3rzeniami

unique_permutations_wiki = set(permutations(example_wiki))

print(len(unique_permutations_wiki)) # -> (len - length of collection), 30 according to wiki article

1 użytkowników online, w tym zalogowanych: 0, gości: 1