- #include <iostream>
- #include <fstream>
- #include <algorithm>
- #include <vector>
- int main() {
- int n, dim;
- std::cin >> n >> dim;
- std::vector<std::vector<int>> a(n, std::vector<int>(dim + 1, 0));
- for (int i = 0; i < n; i++) {
- a[i][0] = i + 1;
- for (int j = 1; j < dim + 1; j++) {
- std::cin >> a[i][j];
- a[i][j] *= 2;
- }
- }
- int* b = new int[dim + 1]();
- int mid1, mid2;
- for (int i = 1; i < dim + 1; i++) {
- std::nth_element(a.begin(), a.begin() + n / 2, a.end(),
- [&](const std::vector<int>& left, const std::vector<int>& right) {
- return left[i] < right[i];
- }
- );
- std::nth_element(a.begin(), a.begin() + n / 2 - 1, a.begin() + n / 2,
- [&](const std::vector<int>& left, const std::vector<int>& right) {
- return left[i] < right[i];
- }
- );
- mid1 = a[n / 2 - 1][i];
- mid2 = a[n / 2][i];
- b[i] = int((long long (mid1) + long long(mid2)) / 2);
- }
- int powdim = pow(3, dim);
- std::vector<std::vector<int>> group(powdim);
- int code, digit;
- for (int i = 0; i < n; i++) {
- code = 0;
- for (int j = 1; j < dim + 1; j++) {
- digit = (a[i][j] < b[j]) ? 0 : ((a[i][j] == b[j]) ? 1 : 2);
- code = code * 3 + digit;
- }
- group[code].push_back(a[i][0]);
- }
- const int SOURCE = powdim;
- const int SINK = powdim + 1;
- int** cap = new int*[powdim + 2];
- int** flow = new int*[powdim + 2];
- std::vector<std::vector<int>> next(powdim + 2);
- for (int i = 0; i < powdim + 2; i++) {
- cap[i] = new int[powdim + 2]();
- flow[i] = new int[powdim + 2]();
- }
- int fstdigit;
- for (code = 0; code < powdim; code++) {
- fstdigit = code / (powdim / 3);
- if (!group[code].empty()) {
- if (fstdigit == 0) {
- cap[SOURCE][code] = group[code].size();
- next[SOURCE].push_back(code);
- next[code].push_back(SOURCE);
- }
- else {
- cap[code][SINK] = group[code].size();
- next[code].push_back(SINK);
- next[SINK].push_back(code);
- }
- }
- }
- bool compat;
- int cop1, cop2, dig1, dig2;
- for (int c1 = 0; c1 < powdim / 3; c1++) {
- for (int c2 = 2 * powdim / 3; c2 < powdim; c2++) {
- cop1 = c1;
- cop2 = c2;
- compat = true;
- for (int i = 1; i < dim + 1; i++) {
- dig1 = cop1 % 3;
- dig2 = cop2 % 3;
- cop1 /= 3;
- cop2 /= 3;
- if ((dig1 == 0 && dig2 == 0) || (dig1 == 2 && dig2 == 2)) {
- compat = false;
- break;
- }
- }
- if (compat) {
- cap[c1][c2] = std::min(group[c1].size(), group[c2].size());
- next[c1].push_back(c2);
- next[c2].push_back(c1);
- }
- }
- }
- int* height = new int[powdim + 2]();
- int* excess = new int[powdim + 2]();
- for (int c = 0; c < powdim; c++)
- height[SOURCE] += (!group[c].empty()) ? 1 : 0;
- height[SOURCE]++;
- std::vector<std::vector<int>> heightExcessCodes(1 + 2 * height[SOURCE]);
- for (int c = 0; c < powdim; c++) {
- if (cap[SOURCE][c] > 0) {
- excess[c] = cap[SOURCE][c];
- flow[SOURCE][c] = cap[SOURCE][c];
- flow[c][SOURCE] = -cap[SOURCE][c];
- heightExcessCodes[height[c]].push_back(c);
- }
- }
- int h, f, extra, minHeight;
- while (true) {
- h = heightExcessCodes.size() - 1;
- while (h >= 0 && heightExcessCodes[h].empty())
- h--;
- if (h < 0)
- break;
- f = heightExcessCodes[h].back();
- heightExcessCodes[h].pop_back();
- while (true) {
- for (int to : next[f]) {
- if (height[to] < height[f] && flow[f][to] < cap[f][to]) {
- extra = std::min(cap[f][to] - flow[f][to], excess[f]);
- if ((excess[to] == 0) && to != SINK && to != SOURCE)
- heightExcessCodes[height[to]].push_back(to);
- flow[f][to] += extra;
- flow[to][f] = -flow[f][to];
- excess[f] -= extra;
- excess[to] += extra;
- if (excess[f] == 0)
- break;
- }
- }
- if (excess[f] == 0)
- break;
- minHeight = 2 * height[SOURCE];
- for (int to : next[f]) {
- if (flow[f][to] < cap[f][to])
- minHeight = std::min(minHeight, height[to]);
- }
- height[f] = minHeight + 1;
- }
- }
- if (excess[SINK] != n / 2) {
- std::cout << "NO";
- return 0;
- }
- std::cout << "YES" << '\n';
- int id1, id2;
- for (int c1 = 0; c1 < powdim / 3; c1++) {
- for (int c2 = 2 * powdim / 3; c2 < powdim; c2++) {
- while (flow[c1][c2] > 0) {
- flow[c1][c2]--;
- id1 = group[c1].back();
- group[c1].pop_back();
- id2 = group[c2].back();
- group[c2].pop_back();
- std::cout << id1 << ' ' << id2 << '\n';
- }
- }
- }
- delete[] b;
- delete[] height;
- delete[] excess;
- for (int i = 0; i < powdim + 2; i++) {
- delete[] flow[i];
- delete[] cap[i];
- }
- delete[] flow;
- delete[] cap;
- return 0;
- }