#include <vector>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <tuple>
using namespace std;

const int INF = 1 << 28;
int N, D;
int p[51][51], dp[51][51][51];
tuple<int, int, int> pre[51][51][51];
bool can[51][51][51];

tuple<int, int, int> min_tuple(tuple<int, int, int> A, tuple<int, int, int> B) {
  int a1, a2, a3, b1, b2, b3;
  tie(a1, a2, a3) = A, tie(b1, b2, b3) = B;
  if(a2 < b2) return A;
  return B;
}

int main() {
  cin >> N >> D;
  for(int i=0; i<N; i++) {
    for(int j=0; j<D; j++) {
      cin >> p[i][j];
    }
  }

  fill(dp[0][0], dp[D+1][0], INF);
  const tuple<int, int, int> INIT(INF, INF, INF);
  fill(pre[0][0], pre[D+1][0], INIT);
  for(int i=0; i<N; i++) dp[0][i][0] = 0;
  for(int i=0; i<D; i++) {
    for(int j=0; j<N; j++) {
      for(int k=0; k<=i; k++) {
        if(dp[i][j][k] == INF) continue;
        
        // if(i == D) continue;
        for(int x=0; x<N; x++) {
          int ncost = dp[i][j][k] + p[x][i];
          int nmove = k + (j != x);
          if(dp[i+1][x][nmove] >= ncost) {
            bool strict = (dp[i+1][x][nmove] > ncost);
            dp[i+1][x][nmove] = ncost;

            if(strict) pre[i+1][x][nmove] = make_tuple(i, j, k);
            else pre[i+1][x][nmove] = min_tuple(pre[i+1][x][nmove], make_tuple(i, j, k));
          }
        }
      }
    }
  }

  for(int i=0; i<=D; i++) {
    for(int j=0; j<N; j++) {
      for(int k=0; k<=i; k++) {
        if(dp[i][j][k] == INF) continue;
        // fprintf(stderr, "dp[%d][%d][%d] = %d, ", i, j, k, dp[i][j][k]);
        int a, b, c; tie(a, b, c) = pre[i][j][k];
        // fprintf(stderr, "pre = (%d, %d, %d)\n", a, b, c);
      }
    }
  }

  int min_cost = INF, min_move = INF, min_hotel = INF;
  for(int hotel=0; hotel<N; hotel++) {
    for(int mv=0; mv<D; mv++) {
      int val = dp[D][hotel][mv];
      if(min_cost > val) {
        min_cost = val;
        min_move = mv, min_hotel = hotel;
      }
      else if(min_cost == val) {
        if(min_move > mv) {
          min_move = mv;
          min_hotel = hotel;
        }
        else if(min_move == mv) {
          min_hotel = min(min_hotel, hotel);
        }
      }
    }
  }

  for(int hotel=0; hotel<N; hotel++) {
    if(dp[D][hotel][min_move] == min_cost) {
      can[D][hotel][min_move] = true;
    }
  }

  // cerr << "passed 1" << endl;
  for(int i=D-1; i>=0; i--) {
    for(int j=0; j<N; j++) {
      for(int k=0; k<D; k++) {
        for(int x=0; x<N; x++) {
          // fprintf(stderr, "%lld, %lld, %lld, %lld\n", i, j, k, x);
          int ncost = dp[i][j][k] + p[x][i];
          int nmove = k + (x != j);
          if(dp[i+1][x][nmove] == ncost and can[i+1][x][nmove]) {
            can[i][j][k] = true;
          }
        }
      }
    }
  }

  // cout << "passed" << endl;
  vector<int> ans;
  int cur = -1, mv = 0;
  for(int i=0; i<N; i++) {
    if(can[1][i][0]) {
      cur = i;
      ans.push_back(i);
      break;
    }
  }

  for(int i=1; i<D; i++) {
    for(int x=0; x<N; x++) {
      int nmove = mv + (x != cur);
      if(can[i+1][x][nmove]) {
        cur = x;
        ans.push_back(x);
        mv = nmove;
        break;
      }
    }
  }

  // fprintf(stderr, "min_cost = %d, min_move = %d, min_hotel = %d\n", min_cost, min_move, min_hotel);
  /*
  vector<int> ans;
  int idx = D, hotel = min_hotel, mv = min_move;
  for(; idx > 0; idx--) {
    ans.push_back(hotel);
    int a, b, c; tie(a, b, c) = pre[idx][hotel][mv];
    hotel = b; mv = c;
    // fprintf(stderr, "hotel = %d, mv = %d\n", hotel, mv);
  }
  reverse(ans.begin(), ans.end());
  */

  printf("%d %d\n", min_cost, min_move);
  for(int i=0; i<D; i++) {
    printf("%d\n", ans[i] + 1);
  }
  return 0;
}



Measured memory_bytes: 5436