#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<sstream>
#include<string>
using namespace std;
const int INF = 1 << 30;
#define MAX_V 202
typedef pair < int , int > Pi;
int n;
class Primal_Dual{
private:
  struct edge{
    int to, cap, cost, rev;
  };
  int V;
  vector< edge > info[MAX_V];
  int h[MAX_V], dist[MAX_V], prevv[MAX_V], preve[MAX_V];
public:
  void add_edge(int from,int to,int cap,int cost){ //from,to,容量,コスト
    info[from].push_back((edge){to,cap,cost,info[to].size()});
    info[to].push_back((edge){from,0,-cost,info[from].size()-1});
  }
  Primal_Dual(){};
  Primal_Dual(int size):V(size){};
  int min_cost_flow(int s,int t,int f){ //sからtへの最小費用流
    int ret = 0;
    fill_n( h, V, 0);
    while(f > 0){
      priority_queue< Pi, vector< Pi >, greater< Pi > > que;
      fill_n( dist, V, INF);
      que.push(Pi(0,s));
      dist[s] = 0;
      while(!que.empty()){
        Pi p = que.top(); que.pop();
        if(dist[p.second] < p.first) continue;
        for(int i = 0; i < info[p.second].size(); i++){
          edge& e = info[p.second][i];
          if(e.cap > 0 && dist[e.to] > dist[p.second] + e.cost + h[p.second] - h[e.to]){
            dist[e.to] = dist[p.second] + e.cost + h[p.second] - h[e.to];
            prevv[e.to] = p.second, preve[e.to] = i;
            que.push(Pi(dist[e.to],e.to));
          }
        }
      }
      if(dist[t] == INF) return -1;
      for(int v = 0; v < V; v++) h[v] += dist[v];
      int d = f;
      for(int v = t; v != s; v = prevv[v]){
        d = min( d, info[prevv[v]][preve[v]].cap);
      }
      f -= d;
      ret += d * h[t];
      for(int v = t; v != s; v = prevv[v]){
        edge& e = info[prevv[v]][preve[v]];
        e.cap -= d;
        info[v][e.rev].cap += d;
      }
    }
    return ret;
  }
  void dump(char F[][100]){
    vector< string > ret;
    for(int i = 0; i < n; i++){
      for(int j = 0; j < info[i].size(); j++){
        if(info[i][j].cap == 0){
          const int pos = info[i][j].to - n;
          if(F[i][pos] == '.'){
            stringstream ss;
            ss << i + 1 << " " <<  pos + 1 << " write";
              ret.push_back(ss.str());
          }
          for(int k = 0; k < n; k++){
            if(k == pos) continue;
            if(F[i][k] == 'o'){
              stringstream ss;
              ss << i + 1 << " " << k + 1 << " erase";
              ret.push_back(ss.str());
            }
          }
          break;
        }
      }
    }
    cout << ret.size() << endl;
    for(int i = 0 ; i < ret.size(); i++){
      cout << ret[i] << endl;
    }
  }
};

#define rep(i,n) for(int i=0;i<n;i++)

int main(){
  int W[100][100], E[100][100];
  char F[100][100];

  cin >> n;
  const int from = n * 2, to = n * 2 + 1;
  rep(i,n) rep(j,n) cin >> W[i][j];
  rep(i,n) rep(j,n) cin >> E[i][j];
  rep(i,n) rep(j,n) cin >> F[i][j];

  Primal_Dual Graph(n * 2 + 2);
  rep(i,n) {
    Graph.add_edge( from, i, 1, 0); //各行へ
    Graph.add_edge( n + i, to, 1, 0); // 吸収
  }

  rep(i,n) {
    rep(j,n) {
      int cost = 0;
      if(F[i][j] == '.') cost += W[i][j]; //そこに○かくと
      rep(k,n) {
        if(j == k) continue;
        if(F[i][k] == 'o') cost += E[i][k]; //ここの○は消さねば
      }
      Graph.add_edge( i, n + j, 1, cost);
    }
  }
  cout << Graph.min_cost_flow(from, to, n) << endl;
  Graph.dump(F);
}

Measured memory_bytes: 1876