int n, m, vis[1005], mat[1005], pre[1005]; longlong g[505][1005]; longlong w[1005], slack[1005];
intmain(){ scanf("%d%d", &n, &m); memset(g, ~0x3f, sizeof(g)); for (int i = 1; i <= m; i++) { int u, v, w; scanf("%d%d%d", &u, &v, &w); g[u][n + v] = w; } for (int i = 1; i <= n; i++) { // 设置初始顶标 w[i] = ~0x3f3f3f3f3f3f3f3f; for (int j = n + 1; j <= n + n; j++) w[i] = max(w[i], (longlong)g[i][j]); } for (int i = 1; i <= n; i++) { memset(vis, 0, sizeof(vis)); // vis 表示是否在 T 中 memset(slack, 0x3f, sizeof(slack)); memset(pre, 0, sizeof(pre)); int now = i, ri = 0; // now 为当前搜索的左部点,ri 为与之匹配的右部点 while (1) { int id = 0; longlong delta = 0x3f3f3f3f3f3f3f3f; for (int j = n + 1; j <= n + n; j++) if (!vis[j]) { longlong val = w[now] + w[j] - g[now][j]; if (val < slack[j]) slack[j] = val, pre[j] = ri; // now 是新加入交错树的点,所以首先要用其更新每个点的 slack 和 pre if (slack[j] < delta) delta = slack[j], id = j; } w[i] -= delta; for (int j = n + 1; j <= n + n; j++) if (vis[j]) w[j] += delta, w[mat[j]] -= delta; else slack[j] -= delta; vis[ri = id] = 1; if (mat[ri]) now = mat[ri]; elsebreak; } while (ri) { mat[ri] = mat[pre[ri]]; if (!pre[ri]) {mat[ri] = i; break;} ri = pre[ri]; } } longlong ans = 0; for (int i = 1; i <= n + n; i++) ans += w[i]; printf("%lld\n", ans); for (int i = n + 1; i <= n + n; i++) printf("%d ", mat[i]); puts(""); return0; }