<tb@panthema.net>
<http://www.gnu.org/licenses/>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <vector>
#include "alg_game.h"
#include "debug.h"
#include "graph6.h"
static const bool debug = true;
using list_type = std::vector<size_t>;
bool contains(const list_type& list, size_t item)
{
return std::find(list.begin(), list.end(), item) != list.end();
}
list_type remove(const list_type& list, size_t rmitem)
{
list_type out;
for (auto item : list)
{
if (item != rmitem)
out.push_back(item);
}
return out;
}
list_type insert(const list_type& list, size_t initem)
{
list_type out = list;
out.push_back(initem);
std::sort(out.begin(), out.end());
return out;
}
list_type complement(const list_type& list, size_t max)
{
list_type out;
list_type::const_iterator li = list.begin();
for (size_t i = 0; i < max; ++i)
{
if (li != list.end() && *li == i)
++li;
else
out.push_back(i);
}
return out;
}
struct Matrix
{
int m_rows, m_cols;
const int * m_data;
Matrix(int rows, int cols, const int* data)
: m_rows(rows), m_cols(cols), m_data(data)
{ }
size_t ground_size() const
{
return m_cols;
}
const int & cell(int row, int col) const
{
return m_data[m_cols * row + col];
}
bool are_dependent(const list_type& list) const
{
std::vector<int> sum(m_rows, 0);
for (auto v : list)
{
for (int r = 0; r < m_rows; ++r)
{
sum[r] += cell(r, v);
sum[r] %= 2;
}
}
return std::accumulate(sum.begin(), sum.end(), 0) == 0;
}
bool are_independent(const list_type& list) const
{
return !are_dependent(list);
}
};
static const int C_3_4[] =
{
1, 0, 0, 0, 1, 0, 1, 1,
0, 1, 0, 0, 1, 1, 0, 1,
0, 0, 1, 0, 1, 1, 1, 0,
0, 0, 0, 1, 0, 1, 1, 1,
};
static const int M_K_3_3_Star[] =
{
1, 0, 0, 0, 1, 0, 0, 1, 1,
0, 1, 0, 0, 1, 1, 0, 0, 1,
0, 0, 1, 0, 0, 1, 1, 0, 1,
0, 0, 0, 1, 0, 0, 1, 1, 1,
};
static const int R_10[] =
{
1, 0, 0, 0, 0, 1, 1, 0, 0, 1,
0, 1, 0, 0, 0, 1, 1, 1, 0, 0,
0, 0, 1, 0, 0, 0, 1, 1, 1, 0,
0, 0, 0, 1, 0, 0, 0, 1, 1, 1,
0, 0, 0, 0, 1, 1, 0, 0, 1, 1,
};
static const int R_12[] =
{
1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0,
0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0,
0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0,
0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1,
0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1,
0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1,
};
static const int _R_12[] =
{
1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0,
0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0,
0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1,
0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1,
0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1,
};
static const int G_W_4[] =
{
1, 1, 1, 0, 0, 0, 0, 0,
1, 0, 0, 1, 0, 1, 0, 0,
0, 1, 0, 1, 1, 0, 1, 0,
0, 0, 1, 0, 1, 0, 0, 1,
0, 0, 0, 0, 0, 1, 1, 1,
};
struct Circuits
{
size_t m_ground_size;
std::vector<list_type> m_circuits;
explicit Circuits(const Matrix& M)
: m_ground_size(M.ground_size())
{
DBGG("circuits:");
for (size_t i = 1; i < M.ground_size(); ++i)
{
choose(M.ground_size(), i, [&](const std::vector<size_t>& curr)
{
if (M.are_dependent(curr))
{
DBGG(curr << " -> " << M.are_dependent(curr));
m_circuits.push_back(curr);
}
return true;
});
}
}
size_t ground_size() const
{
return m_ground_size;
}
bool contains_circuit(const list_type& list) const
{
list_type out(list.size());
for (auto c : m_circuits)
{
list_type::iterator end =
std::set_intersection(list.begin(), list.end(),
c.begin(), c.end(),
out.begin());
if (end == out.begin() + c.size())
{
return true;
}
}
return false;
}
bool find_circuit(const list_type& list, list_type& outcycle) const
{
list_type out(list.size());
for (auto c : m_circuits)
{
list_type::iterator end =
std::set_intersection(list.begin(), list.end(),
c.begin(), c.end(),
out.begin());
if (end == out.begin() + c.size())
{
outcycle = c;
return true;
}
}
abort();
return false;
}
std::vector<list_type> m_bases;
void calc_bases(int rank)
{
DBGG("bases:");
choose(ground_size(), rank, [&](const std::vector<size_t>& curr)
{
if (!contains_circuit(curr))
{
DBGG(curr << " -> " << contains_circuit(curr));
m_bases.push_back(curr);
}
return true;
});
}
unsigned int rank(const list_type& list) const
{
list_type out(list.size());
unsigned int max = 0;
for (auto b : m_bases)
{
list_type::iterator end =
std::set_intersection(list.begin(), list.end(),
b.begin(), b.end(),
out.begin());
max = std::max<unsigned int>(max, end - out.begin());
}
return max;
}
};
static std::vector<list_type> circuits_F_7 = {
{ 0, 1, 4 }, { 0, 3, 6 }, { 0, 2, 5 }, { 1, 3, 5 }, { 1, 2, 6 }, { 2, 3, 4 }, { 4, 5, 6 }
};
static std::vector<list_type> circuits_F_7_ = {
{ 0, 1, 4 }, { 0, 3, 6 }, { 0, 2, 5 }, { 1, 3, 5 }, { 1, 2, 6 }, { 2, 3, 4 }
};
bool test_block_matroid(const Circuits& C)
{
size_t ground = C.ground_size();
std::vector<int> item(ground, 0);
while (1)
{
list_type list;
for (size_t i = 0; i < item.size(); ++i)
{
if (item[i]) list.push_back(i);
}
unsigned int r = C.rank(list);
if (2 * r < list.size())
{
std::cerr << item << " - " << list << " - rank " << r << "\n";
return false;
}
size_t i = 0;
while (item[i] && i < ground)
item[i++] = 0;
if (i < ground) item[i] = 1;
else break;
}
return true;
}
class BaseComplementer
{
public:
unsigned int max;
explicit BaseComplementer(unsigned int m)
: max(m)
{ }
Tree operator () (const Tree& tree)
{
Tree comp;
Tree::const_iterator t = tree.begin();
for (size_t i = 0; i < max; ++i)
{
if (t != tree.end() && *t == i)
++t;
else
comp.push_back(i);
}
assert(tree.size() == comp.size());
return comp;
}
};
void play_game(const Circuits& C)
{
static const bool debug = false;
const std::vector<list_type>& bases = C.m_bases;
DBGG("checking " << bases.size() << " bases:");
std::cout << "graph G {\n"
<< " graph [splines=false,K=2.6]\n"
<< " node []\n"
<< " edge []\n";
TauGraph tau;
for (auto base : bases)
{
list_type cbase = complement(base, C.ground_size());
if (C.contains_circuit(cbase)) continue;
DBGG(base << " / " << cbase << " -> ");
for (size_t i = 0; i < C.ground_size(); ++i)
{
if (contains(base, i))
{
list_type clist = insert(cbase, i);
DBGG(" " << clist);
list_type circuit;
C.find_circuit(clist, circuit);
DBGG(" -> " << circuit);
std::vector<list_type> UElinks;
for (auto sw : circuit)
{
if (sw == i) continue;
list_type cxlist = insert(remove(base, i), sw);
list_type cylist = insert(remove(cbase, sw), i);
DBGG(" -- " << i << " <-> " << sw << " -- " << cxlist << " / " << cylist <<
" -- " << C.contains_circuit(cxlist) << " / " << C.contains_circuit(cylist));
if (!C.contains_circuit(cxlist) && !C.contains_circuit(cylist))
UElinks.push_back(cxlist);
}
if (UElinks.size() == 1)
{
std::cout << vector_join(base, "") << " -- " << vector_join(UElinks[0], "") << std::endl;
TauGraph::vertex_iterator basev = tau.discover_vertex(Tree(base));
TauGraph::vertex_iterator destv = tau.discover_vertex(Tree(UElinks[0]));
tau.add_edge(basev, destv, TauEdge(1, 0, 0));
}
}
else
{
list_type clist = insert(base, i);
DBGG(" " << clist);
list_type circuit;
C.find_circuit(clist, circuit);
DBGG(" -> " << circuit);
std::vector<list_type> UElinks;
for (auto sw : circuit)
{
if (sw == i) continue;
list_type cxlist = insert(remove(base, sw), i);
list_type cylist = insert(remove(cbase, i), sw);
DBGG(" -- " << i << " <-> " << sw << " -- " << cxlist << " / " << cylist <<
" -- " << C.contains_circuit(cxlist) << " / " << C.contains_circuit(cylist));
if (!C.contains_circuit(cxlist) && !C.contains_circuit(cylist))
UElinks.push_back(cxlist);
}
if (UElinks.size() == 1)
{
std::cout << vector_join(base, "") << " -- " << vector_join(UElinks[0], "") << std::endl;
TauGraph::vertex_iterator basev = tau.discover_vertex(Tree(base));
TauGraph::vertex_iterator destv = tau.discover_vertex(Tree(UElinks[0]));
tau.add_edge(basev, destv, TauEdge(1, 0, 0));
}
}
}
}
std::cout << "}\n";
bool conn = tau.is_connected();
std::cerr << "connected: " << conn << std::endl;
if (!conn) return;
std::cout << "// RESULT"
<< " tau_num_vertex=" << tau.num_vertex()
<< " tau_num_edge=" << tau.num_edge()
<< " tau_min_degree=" << tau.get_min_degree()
<< " tau_max_degree=" << tau.get_max_degree()
<< " tau_avg_degree=" << tau.get_avg_degree()
<< " tau_regularity=" << tau.get_regularity()
;
unsigned int dia = tau.get_ue_diameter_generic(C.m_ground_size, BaseGraph(),
BaseComplementer(C.m_ground_size));
std::cout << " ue_diameter=" << dia;
std::cout << std::endl;
if (dia != C.m_ground_size / 2) abort();
if (!conn) abort();
}
void process_fixed()
{
Circuits C(Matrix(4, 8, G_W_4));
C.calc_bases(4);
test_block_matroid(C);
play_game(C);
}
void process_file(std::istream& is)
{
std::string line;
unsigned int n, k, f, count;
is >> n >> k >> f >> count;
std::cerr << "// n = " << n << " - k = " << k << " - count = " << count << std::endl;
for (size_t i = 0; i < count; ++i)
{
std::vector<int> data(n * k, 0);
for (size_t vecval = 0; vecval < n; ++vecval)
{
unsigned int v;
is >> v;
for (size_t j = 0; j < k; ++j)
{
data[j * n + vecval] = (v & 1);
v /= 2;
}
}
Circuits C(Matrix(k, n, data.data()));
C.calc_bases(k);
if (!test_block_matroid(C)) {
std::cerr << "Not a block matroid!" << std::endl;
continue;
}
play_game(C);
}
}
int main()
{
process_file(std::cin);
return 0;
}