/* * Author:heroming * File:heroming.cpp * Time:2020/10/16 11:45:42 */ #include <vector> #include <list> #include <set> #include <map> #include <deque> #include <queue> #include <stack> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iostream> #include <string> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <cstring> #include <ctime> #include <unordered_map> using namespace std; typedef long long lint; const int maxd = 5; const int maxn = 200010; const int maxm = 1 << maxd; int d, n; int u[maxn][maxd]; // origin points int v[maxn][maxm]; // points info for each mask int s[maxm]; // max value for each mask in visited set A set<pair<int, int>> t[maxm]; // all value for each mask of every node in unvisited set B int main() { scanf("%d%d", &d, &n); for (int k = 0; k < n; ++ k) { for (int i = 0; i < d; ++ i) { scanf("%d", &u[k][i]); } } const int m = 1 << d; for (int e = 0; e < m; ++ e) { for (int k = 0; k < n; ++ k) { for (int i = 0; i < d; ++ i) { if (e & (1 << i)) { v[k][e] += u[k][i]; } else { v[k][e] -= u[k][i]; } } // visited set initially has point 0 if (k == 0) { s[e] = v[k][e]; } else { t[e].insert({v[k][e], k}); } } } lint ans = 0; // prim algorithm, each time pick a point with max distance for (int k = 1; k < n; ++ k) { int w = -1, p = -1; // pick the max distance point for (int e = 0; e < m; ++ e) { auto l = *t[e].begin(); if (w < s[e] - l.first) { p = l.second; w = s[e] - l.first; } } ans += w; // update max value of each mask in A // and erase picked point info from B for (int e = 0; e < m; ++ e) { t[e].erase({v[p][e], p}); s[e] = max(s[e], v[p][e]); } } printf("%lld\n", ans); return 0; }