import java.io.PrintWriter
import java.util.*
import java.math.*
import java.lang.*
import kotlin.comparisons.*

val pw = PrintWriter(System.out)
val MOD: Long = (1e+9 + 7).toLong()

data class Point(val next: Int, var cost: Int)
fun dijkstra(s: Int, n: Int, edges: Array<MutableList<Point>>): List<Pair<Int, Int>> {
    val distance = Array(n) { 100000 }.apply { this[s] = 0 }
    val prev = Array(n) { -1 }
    val que: Queue<Point> = ArrayDeque<Point>()
    que.add(Point(s, 0))
    while(!que.isEmpty()) {
        val (current, currentCost) = que.poll()
        edges[current].forEach { edge ->
            val (next, cost) = edge
            val nextCost = currentCost + cost
            if(distance[next] > nextCost) {
                distance[next] = nextCost 
                prev[next] = current
                que.add(Point(next, nextCost))
            }
        }
    }
    val path = mutableListOf<Pair<Int, Int>>()
    for(current in 0 until n) {
        var cur = current
        while(cur != -1) {
            val next = prev[cur]
            if(next != -1 && cur != -1) {
                path.add(Pair(next, cur))
            }
            cur = next
        }
    }
    return path
}

fun main(args: Array<String>) {
    val (n, m) = readListOfInt()
    val edges = Array(n) { mutableListOf<Point>() }
    for(i in 0 until m) {
        val (a, b, c) = readListOfInt()
        edges[a-1].add(Point(b-1, c))
        edges[b-1].add(Point(a-1, c))
    }
    val ansEdges = edges.toList().map { it.map { it.next }.toMutableList() }
    for(s in 0 until n) {
        val removeEdges = dijkstra(s, n, edges)
        removeEdges.forEach { edge ->
            val (a, b) = edge
            ansEdges[a].remove(b)
            ansEdges[b].remove(a)
        }
    }
    println(ansEdges.flatten().size/2)

    pw.flush()
}

/****** Declared Functions and Data Structures ******/
// IO
fun read() = readLine()!!
fun readInt() = read().toInt()
fun readLong() = read().toLong()
fun readDouble() = read().toDouble()
fun readListOfString() = read().split(" ")
fun readListOfInt() = readListOfString().map { it.toInt() }
fun readListOfLong() = readListOfString().map { it.toLong() }
fun readListOfDouble() = readListOfString().map { it.toDouble() }

fun Double.format(digits: Int) = String.format("%.${digits}f", this)
fun Float.format(digits: Int) = String.format("%.${digits}f", this)

fun print(value: Any) { pw.print(value) }
fun println(value : Any) { pw.println(value) }

// Extensions
fun<T> List<T>.toBuckets(): Map<T, Int>
    = this.groupBy { it }.mapValues { it.value.size }

fun<T: Comparable<T>> List<T>.upperBound(element: T, fromIndex: Int=0, toIndex: Int=this.size): Int {
    var l = fromIndex
    var r = toIndex
    while(l < r) {
        val mid = (l+r) / 2
        if(element >= this[mid]) { 
            l = mid + 1
        } else {
            r = mid
        }
    }
    return l
}

fun<T: Comparable<T>> List<T>.lowerBound(element: T, fromIndex: Int=0, toIndex: Int=this.size): Int {
    var l = fromIndex
    var r = toIndex
    while(l < r) {
        val mid = (l+r) / 2
        if(element <= this[mid]) { 
            r = mid
        } else {
            l = mid + 1
        }
    }
    return r 
}

fun <K, V> Map<K, V>.toMutableMap(): MutableMap<K, V> = HashMap(this)

// Util Functions
fun Long.makeDivisors(): List<Long> {
    val divisors = mutableListOf<Long>()
    for(i in 1L .. Math.sqrt(this.toDouble()).toLong()+1L) {
        if(this % i == 0L) {
            divisors.add(i)
            if(i != this/i) {
                divisors.add(this/i)
            }
        }
    }
    return divisors.distinct().sorted()
}

fun Long.isPrime(): Boolean {
    if(this==1L) return false
    for(i in 2L .. Math.sqrt(this.toDouble()).toLong() + 1L) {
        if(this % i == 0L && this != i) {
            return false
        }
    }
    return true
}


fun<T> permutations(src: List<T>): List<List<T>> {
    if(src.size == 1) return listOf(src)
    val perms = mutableListOf<List<T>>()
    val insertElement = src[0]
    permutations(src.drop(1)).forEach { perm ->
        for(i in 0..perm.size) {
            val newPerm = perm.toMutableList()
            newPerm.add(i, insertElement)
            perms.add(newPerm.toList())
        }
    }
    return perms
}

// return nCr, if you want nCr, please access v[n][r]
fun combinations(n: Long): List<List<Long>> {
    val v = (0..n).map { (0..n).map{0L}.toMutableList() }.toMutableList()
    for(i in 0 until v.size) {
        v[i][0] = 1L
        v[i][i] = 1L
    }
    for(i in 0 until v.size) {
        for(j in 1 until i) {
            v[i][j] = (v[i-1][j-1] + v[i-1][j]) % MOD
        }
    }
    return v.map { it.toList() }.toList()
}

fun repeatedModPow(a: Long, n: Long, mod: Long): Long = 
    when {
        n == 1L -> a % mod
        n % 2L == 1L -> (a * repeatedModPow(a, n-1L, mod)) % mod
        else -> {
            val tmp = repeatedModPow(a, n / 2L, mod)
            (tmp * tmp) % mod
        }
    }

// return nCr % MOD
fun modnCkWithoutArray(n: Long, k: Long, mod: Long): Long {
    var ret = 1L
    val min = Math.min(k, n-k)
    // まず分母の計算
    for(i in n downTo (n - min + 1)) {
        ret = ret * i % mod
    }
    for(i in min downTo 1) {
        ret = ret * repeatedModPow(i, (mod - 2L), mod) % mod
    }
    return ret
}

// return nCr % MOD
fun modnCk(n: Int, k: Int, mod: Long): Long {
    val factorials = Array(n+1) { 0L }.apply {
        this[0] = 1L
        if(this.size > 1) this[1] = 1L
    }
    val inverses = Array(n+1) { 0L }.apply {
        this[0] = 1L
        if(this.size > 1) this[1] = 1L
    }
    val factorialInverses = Array(n+1) { 0L }.apply {
        this[0] = 1L
        if(this.size > 1) this[1] = 1L
    }
    for(i in 2 .. n) {
        factorials[i] = (factorials[i-1] * i.toLong() % mod)
        inverses[i] = (mod - inverses[mod.toInt() % i] * (mod / i.toLong()) % mod)
        factorialInverses[i] = (factorialInverses[i-1] * inverses[i] % mod)
    }

    return factorials[n] % mod * (factorialInverses[k] * factorialInverses[n-k] % mod) % mod
}

// should be a >= b
fun gcd(a: Long, b: Long): Long = 
    if(b == 0L) a else gcd(b, a % b)

// shoud be a >= b
fun lcm(a: Long, b: Long): Long = 
    a / gcd(a, b) * b

fun sumDigits(num_: Long): Long {
    var num = num_
    var rtn: Long = 0
    while(num != 0.toLong()) {
        val tmp = num % 10
        rtn += tmp
        num /= 10
    }
    return rtn
}

fun Double.isDecimal(): Boolean = ((this - Math.floor(this)) != 0.0)

// Data Structures

class UnionFind(private val n: Int) {
    private val parent: Array<Int> = Array(n) { 0 }
    private val rank: Array<Int> = Array(n) { 0 }
    private val size: Array<Int> = Array(n) { 0 }

    init {
        for(i in 0 until n) {
            parent[i] = i
            rank[i] = 1
            size[i] = 1
        }
    }

    fun union(u: Int, v: Int) {
        var x = root(u)
        var y = root(v)
        if(x != y) {
            if(rank[y] < rank[x]) {
                val tmp = y 
                y = x
                x = tmp 
            }
            parent[x] = y
            rank[y] += rank[x]
            rank[x] = -1
            val totalSize = size[x] + size[y]
            size[x] = totalSize
            size[y] = totalSize
        }
    }

    fun root(u: Int): Int {
        var x = u
        while(parent[x] != x) {
            x = parent[x]
        }
        return x 
    }

    fun size(u: Int): Int = size[root(u)]
}


Measured memory_bytes: 45520