I see a solution with Permutation in Combinatorial Analysis.
First we must get the combination of the elements in the example: To1, To2, To3, To4, B1, B2, C1, C2, C3, D1. Then simply delete those with adjacent identical letters.
Well, permutation has factorial order O(n!) (being n the number of elements) and 10! of the example would generate 3.628.800 of possibilities. 
However, we can optimize the algorithm by generating only the combinations that matter, in two ways:
- Ignoring a combination (and all derived combinations) if the next letter repeats the current one. For example, if we are mounting a combination and we have 
A, we’ll skip the combination AA and all its derivations (AAB, AAC, ...). 
- Ignoring iterations with repeated letters. Although we have 4 letters To, we don’t need to test the combinations starting with all of them. We only need to test one element corresponding to each letter.
 
To tell you the truth I don’t know how to analyze the order of complexity of this optimization, but what I can say is that the more repeat items there are, the less possibilities will be tested and the faster we will get the result.
Being m the number of letters (ignoring the repetition) and n the total number of elements (counting the repeated ones), we can say that, in the worst case, if we have an element of each letter (m == n), the algorithm will be effectively O(n!). But if we have repetition (m < n), the complexity will be greater than O(m!) and less than O(n!).
I made the following implementation in Java:
public class Distribuicao {
    private List<String> combinacoes = new ArrayList<String>();
    private List<String> becos = new ArrayList<String>();
    private long combinacoesTestadas = 0;
    /**
     * Começa pegando as letras uma a uma e combinando o restante.
     * Note que assim já não precisamos verificar as combinações repetidas,
     * já que usamos a chave única do mapa. 
     */
    public Distribuicao(HashMap<Character, Integer> itens) {
        for (Entry<Character, Integer> e : itens.entrySet()) {
            trocarECombinar(itens, e, "");
        }
    }
    /**
     * Procura novas combinações, ignorando se repetir a letras
     */
    private void combinar(HashMap<Character, Integer> itens, String prefixo) {
        Character ultimo = prefixo.charAt(prefixo.length() - 1);
        boolean itensSobrando = false;
        boolean encontrouNovaPossibilidade = false;
        //verifica cada letra, sem repetir
        for (Entry<Character, Integer> e : itens.entrySet()) {
            //verifica se ainda há um elemento disponível da letra
            if (e.getValue() > 0) {
                itensSobrando = true;
                //verifica se é igual à anterior
                if (!e.getKey().equals(ultimo)) {
                    encontrouNovaPossibilidade = true;
                    //tenta uma nova combinação com a letra atual
                    trocarECombinar(itens, e, prefixo);
                }
            }
        }
        if (!itensSobrando) {
            combinacoesTestadas++;
            combinacoes.add(prefixo);
        } else if (!encontrouNovaPossibilidade) {
            combinacoesTestadas++;
            becos.add("[prefixo = " + prefixo + ", resto = " + itens + "]");
        }
    }
    /**
     * Decrementa a letra usada, acrescenta a atual no prefixo
     * e tenta recursivamente uma nova combinação 
     */
    private void trocarECombinar(
            HashMap<Character, Integer> itens,
            Entry<Character, Integer> e,
            String prefixo) {
        e.setValue(e.getValue() - 1);
        combinar(itens, prefixo + e.getKey().toString());
        e.setValue(e.getValue() + 1);
    }
    public List<String> getCombinacoes() {
        return combinacoes;
    }
    public List<String> getBecos() {
        return becos;
    }
    public long getCombinacoesTestadas() {
        return combinacoesTestadas;
    }
    public static void main(String[] args) {
        //prepara o mapa de teste
        HashMap<Character, Integer> mapa = new HashMap<Character, Integer>();
        mapa.put('A', 4);
        mapa.put('B', 2);
        mapa.put('C', 3);
        mapa.put('D', 1);
        //executa a distribuição
        Distribuicao d = new Distribuicao(mapa);
        //quantidade de combinações testadas
        System.out.println("Combinações testadas: " + d.getCombinacoesTestadas());
        //combinações encontradas 
        System.out.println("Combinações encontradas: " + d.getCombinacoes().size());
        for (String combinacao : d.getCombinacoes()) {
            System.out.println("  -> " + combinacao);
        }
        //combinações onde não houve como continuar     
        System.out.println("Becos sem saída: " + d.getBecos().size());
        for (String beco : d.getBecos()) {
            System.out.println("  -> " + beco);
        }
    }
}
In the example, we have n = 10 and m = 4. This is consistent with the return of the algorithm:
1074 combinations 
462 ""dead ends, that is, situations where there were no letters available to continue and the process was stopped 
							
							
						 
The stopping condition could be without position possible.
– Felipe Avelar