Q:

Combine n sets of files together (randomly and no repetition)

I have the following sets of files:
Every file is discribed as follow type-ID-pageNumber-R.xml i.e jugement_017_3
set 1:
 - Conclusions-009-1-R.xml   
 - Conclusions-010-1-R.xml 
 - Conclusions-011-1-R.xml

set 2:
 - Assignation-043-1-R.xml    
 - Assignation-043-2-R.xml 
 - Assignation-045-1-R.xml 

set 3:
 - Jugement-017-1-R.xml     
 - Jugement-017-2-R.xml  
 - Jugement-017-3-R.xml 
 - Jugement-018-1-R.xml 
 - Jugement-018-2-R.xml 

I want to combine set 1, set 2 and set 3 into set 4 by using the following rules:

Random order of combination (every time we want to combine the files, the order in set 4 will change)
Files of the same type can be placed one after the other if they have the same ID

Set 4:
- Conclusions-009-1-R.xml 
- Jugement-018-1-R.xml 
- Jugement-018-2-R.xml 
- Assignation-043-1-R.xml    
- Assignation-043-2-R.xml
- Conclusions-010-1-R.xml 
- Assignation-045-1-R.xml 
- Conclusions-011-1-R.xml
- Jugement-017-1-R.xml     
- Jugement-017-2-R.xml  
- Jugement-017-3-R.xml

A:

Here's my $0.05 implementation to elaborate on my comment:

store all chapters inside a collection keyed by unique (section,chapter number):
using Section = std::string;
using Page    = int;
using Chapter = int;
using Pages   = icl::interval_set<Page>::type;

struct Module {
    Section section;
    Chapter chapter;

    bool operator<(Module const& o) const;
};

using Table = std::map<Module, Pages>;

As you can see I chose an interval set for storing the page ranges. This makes it easier to do the merging regardless of input order.
So let's do that. I fill the table in "random" order:
 struct Fill { Section s; Chapter c; Page p; };
 for (auto& fill : std::vector<Fill> { 
     { "Jugement",    18 , 2 },
     { "Conclusions", 11 , 1 },
     { "Assignation", 43 , 1 },
     { "Assignation", 43 , 2 },
     { "Conclusions", 10 , 1 },
     { "Jugement",    17 , 3 },
     { "Assignation", 45 , 1 },
     { "Jugement",    17 , 1 },
     { "Conclusions", 9  , 1 },
     { "Jugement",    17 , 2 },
     { "Jugement",    18 , 1 },
 })
 {
     table[{fill.s, fill.c}] += fill.p; // add page to (existing) range
 }

That's all!
Now we can print the modules by section/chapter simply like this:
 std::cout << "------------- table: \n";
 for (auto& r:table)
     std::cout << r << "\n";

Prints:
 ------------- table: 
 Assignation    43  {[1,2]}
 Assignation    45  {[1,1]}
 Conclusions    9   {[1,1]}
 Conclusions    10  {[1,1]}
 Conclusions    11  {[1,1]}
 Jugement   17  {[1,3]}
 Jugement   18  {[1,2]}

Now that we created the required order, let's add some unpredictability (which is subtly different from chaos).
using rv = rw<Table::value_type>;
std::vector<rv> vw(begin(table), end(table));

// blind shuffle
srand(time(0));
std::random_shuffle(vw.begin(), vw.end());

Bam. We have a shuffled view of references to the module table entries. But! Random is not the goal. 
So we find adjacent pairs from matching sections and try to remove those by rotating them away. It's possible, of course, that there will be nothing left to swap with (from another section) in which case we leave the duplicate(s) in the trailing position:
// try to avoid subsequent modules from equal sections (dup)
auto dup     = [](rv a, rv b) { return a.get().first.section == b.get().first.section; };
auto it      = vw.begin();
auto const e = vw.end();

while(it != e) { // bit redundant, could be while(true)
    it = std::adjacent_find(it, e, dup);
    if (it == e) 
        break;

    auto m = std::find_if(it+1, e, [&] (rv r) { return r.get().first.section != it->get().first.section; });

    if (m == e) {
        it = m;
    } else {
        std::rotate(it+1, m, e);
        it = std::adjacent_find(it, e, dup);
    }
}

Of course, print the resulting selection:
std::cout << "------------- selection: \n";
for (auto& r : vw)
    std::cout << r.get() << "\n";

A version that prints some diagnostic/trace information can be seen here:
Live On Coliru

Full Listing
Live On Coliru
#include <boost/bind.hpp>
#include <boost/icl/interval_set.hpp>
#include <boost/tuple/tuple_comparison.hpp>
#include <iomanip>
#include <iostream>
#include <map>

namespace icl = boost::icl;

template<typename T> using rw = boost::reference_wrapper<T>;

using Section = std::string;
using Page    = int;
using Chapter = int;
using Pages   = icl::interval_set<Page>::type;

struct Module {
    Section section;
    Chapter chapter;

    bool operator<(Module const& o) const { return boost::tie(section,chapter) < boost::tie(o.section,o.chapter); }
};

using Table = std::map<Module, Pages>;

static inline std::ostream& operator<<(std::ostream& os, Table::value_type const& p) {
    return os << p.first.section << "\t" << p.first.chapter << "\t" << p.second;
}

int main()
{
    std::cout << std::unitbuf;
    Table table;

    {
        struct Fill { Section s; Chapter c; Page p; };
        for (auto& tup : std::vector<Fill> { 
            { "Jugement",    18 , 2 },
            { "Conclusions", 11 , 1 },
            { "Assignation", 43 , 1 },
            { "Assignation", 43 , 2 },
            { "Conclusions", 10 , 1 },
            { "Jugement",    17 , 3 },
            { "Assignation", 45 , 1 },
            { "Jugement",    17 , 1 },
            { "Conclusions", 9  , 1 },
            { "Jugement",    17 , 2 },
            { "Jugement",    18 , 1 },
        })
        {
            table[{tup.s, tup.c}] += tup.p; // add page to (existing) range
        }
    }

    std::cout << "------------- table: \n";
    for (auto& r:table)
        std::cout << r << "\n";

    {
        using rv = rw<Table::value_type>;
        std::vector<rv> vw(begin(table), end(table));

        // blind shuffle
        srand(time(0));
        std::random_shuffle(vw.begin(), vw.end());

        // try to avoid subsequent modules from equal sections (dup)
        auto dup     = [](rv a, rv b) { return a.get().first.section == b.get().first.section; };
        auto it      = vw.begin();
        auto const e = vw.end();

        while(it != e) // bit redundant, could be while(true)
        {
            std::cout << "------------- STATE: \n";
            for (auto& rv:vw)
                std::cout << rv.get() << (it->get_pointer() == rv.get_pointer()? "*\n":"\n");

            it = std::adjacent_find(it, e, dup);
            if (it == e) 
                break;

            std::cout << "------------- dupes: \n";
            std::cout << "\t" << (it+0)->get() << "\n";
            std::cout << "\t" << (it+1)->get() << "\n";

            auto m = std::find_if(it+1, e, [&] (rv r) { return r.get().first.section != it->get().first.section; });

            if (m == e)
            {
                it = m;
            } else
            {
                std::cout << "------------- rotating to: \n";
                std::cout << "\t" << m->get() << "\n";

                std::rotate(it+1, m, e);

                it = std::adjacent_find(it, e, dup);
            }
        }
        std::cout << "------------- selection: \n";
        for (auto& r : vw)
            std::cout << r.get() << "\n";
    }
}

