#include<algorithm>
#include<cassert>
#include<cctype>
#include<climits>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<iomanip>
#include<map>
#include<numeric>
#include<queue>
#include<vector>
#include<set>
#include<string>
#include<stack>
#include<sstream>
#include<complex>

#define pb push_back
#define clr clear()
#define sz size()
#define fs first
#define sc second

#define rep(i,a) for(int i=0;i<(int)(a);i++)
#define rrep(i,a) for(int i=(int)(a)−1;i>=0;i−−)
#define all(a) (a).begin(),(a).end()
#define EQ(a,b) (abs((a)−(b)) < EPS)
#define INIT(a) memset(a,0,sizeof(a))

using namespace std;
typedef double D;
typedef pair<int,int> P;
typedef long long ll;
typedef vector<int> vi;
typedef vector<string> vs;

const D EPS = 1e-8;
const int INF = 1e8;
const D PI = acos(-1);

int par[10000]; //親ノート&#12441;
int r[10000]; //木の高さ

void init(int n){
  for(int i=0;i<n;i++){par[i] = i;r[i] = 0;}
}

int find(int x){
  if(par[x] == x) return x;
  return par[x] = find(par[x]);
}

void unite(int x,int y){
  x = find(x);
  y = find(y);
  if(x==y)return;
  if(r[x] < r[y])par[x] = y;
  else par[y] = x;
  if(r[x] == r[y])r[x]++;
}

bool same(int x,int y){return find(x)==find(y);}

int v; //頂点数
int m;
int a,b,c;
//辺の定義。必要に応し&#12441;て削る
struct edge{
  int from,to,cost;
  bool operator<(const edge x)const{return cost>x.cost;}
};

vector<edge> G[10000];
void AddEdge(int s,int g,int p){
  G[s].pb((edge){s,g,p});
}

int Kruskal(){
  init(v);
  priority_queue<edge> q;
  rep(i,v)rep(j,G[i].sz)q.push(G[i][j]);

  int res = 0;
  while(q.size()){
    edge e = q.top(); q.pop();
    if(!same(e.from,e.to)){
      res += e.cost;
      unite(e.from,e.to);
    }
  }
  return res;
}

int main(){
  while(cin >> v,v){
    cin >> m;
    rep(i,v)G[i].clr;
    rep(i,m){
      scanf("%d,%d,%d",&a,&b,&c);
      AddEdge(a,b,c/100-1);
    }

    cout << Kruskal() <<  endl;
  }
    
}