Problem:
Score : 400 points

Problem Statement

You are given an undirected connected weighted graph with N vertices and M edges that contains neither self-loops nor double edges.

The i-th (1≤i≤M) edge connects vertex a_i and vertex b_i with a distance of c_i.

Here, a self-loop is an edge where a_i = b_i (1≤i≤M), and double edges are two edges where (a_i,b_i)=(a_j,b_j) or (a_i,b_i)=(b_j,a_j) (1≤i<j≤M).

A connected graph is a graph where there is a path between every pair of different vertices.

Find the number of the edges that are not contained in any shortest path between any pair of different vertices.

Constraints

2≤N≤100

N-1≤M≤min(N(N-1)/2,1000)

1≤a_i,b_i≤N

1≤c_i≤1000

c_i is an integer.

The given graph contains neither self-loops nor double edges.

The given graph is connected.

Input

The input is given from Standard Input in the following format:

N M
a_1 b_1 c_1
a_2 b_2 c_2
:
a_M b_M c_M

Output

Print the number of the edges in the graph that are not contained in any shortest path between any pair of different vertices.

Sample Input 1

3 3
1 2 1
1 3 1
2 3 3

Sample Output 1

1

In the given graph, the shortest paths between all pairs of different vertices are as follows:

The shortest path from vertex 1 to vertex 2 is: vertex 1 → vertex 2, with the length of 1.

The shortest path from vertex 1 to vertex 3 is: vertex 1 → vertex 3, with the length of 1.

The shortest path from vertex 2 to vertex 1 is: vertex 2 → vertex 1, with the length of 1.

The shortest path from vertex 2 to vertex 3 is: vertex 2 → vertex 1 → vertex 3, with the length of 2.

The shortest path from vertex 3 to vertex 1 is: vertex 3 → vertex 1, with the length of 1.

The shortest path from vertex 3 to vertex 2 is: vertex 3 → vertex 1 → vertex 2, with the length of 2.

Thus, the only edge that is not contained in any shortest path, is the edge of length 3 connecting vertex 2 and vertex 3, hence the output should be 1.

Sample Input 2

3 2
1 2 1
2 3 1

Sample Output 2

0

Every edge is contained in some shortest path between some pair of different vertices.

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication14
{
    enum qResult 
    {
        REJECT,
        ENQUEUED,
        HIT
    }

    class Node 
    {
        public Dictionary<int, int> fLen = new Dictionary<int, int>();
        public HashSet<int> Checked = new HashSet<int>();
    }

    class LocalQueue 
    {
        Queue<int> nodeNum = new Queue<int>();
        Queue<int> totalLen = new Queue<int>();
        Queue<HashSet<int>> History = new Queue<HashSet<int>>();
        int targetNum;
        int th;
        
        private void ClrQueue()
        {
            nodeNum.Clear();
            totalLen.Clear();
            History.Clear();
        }

        public LocalQueue(int target, int len, ref Node[] nodeAry, int me)
        {
            targetNum = target;
            th = len;
            foreach(var p in nodeAry[me].fLen.Keys)
            {
                if (p == target) continue;
                nodeNum.Enqueue(p);
                totalLen.Enqueue(nodeAry[me].fLen[p]);
                HashSet<int> h = new HashSet<int>();
                h.Add(me);
                History.Enqueue(h);
            }
        }

        public qResult Enqueue(int nNum, int tLen, HashSet<int> h)
        {
            //探索済みは捨てる
            if (h.Contains(nNum)) return qResult.REJECT;

            //現時点でthより距離が大ならば捨ててよい
            if (tLen >= th) return qResult.REJECT;

            //ターゲットに到達かつ距離が短い場合はHITを返す
            //これ以上の探索は不要なのでQueueを全部破棄する
            if (nNum == targetNum)
            {
                ClrQueue();
                return qResult.HIT;
            }

            //ターゲットに到達してないのでEnqueueして
            //次の階層を探す様にする
            nodeNum.Enqueue(nNum);
            totalLen.Enqueue(tLen);
            HashSet<int> newH = new HashSet<int>(h);
            newH.Add(nNum);
            History.Enqueue(newH);
            return qResult.ENQUEUED;
        }

        public bool Dequeue(out int nNum, out int tLen, out HashSet<int> h) 
        {
            //もしQueue枯渇ならばfalseを返す
            nNum = -1; tLen = -1; h = null;
            if (nodeNum.Count == 0) return false;

            //Dequeueする
            nNum = nodeNum.Dequeue();
            tLen = totalLen.Dequeue();
            h = History.Dequeue();
            return true;
        }

    }

    class Program
    {
        static void Main(string[] args)
        {
            string[] msg = Console.ReadLine().Split(' ');
            int N = int.Parse(msg[0]);
            int M = int.Parse(msg[1]);
            Node[] nodeAry = new Node[N];
            for (int i = 0; i < N; i++) nodeAry[i] = new Node();

            for (int i = 0; i < M; i++) 
            {
                msg = Console.ReadLine().Split(' ');
                int ai = int.Parse(msg[0]) - 1;
                int bi = int.Parse(msg[1]) - 1;
                int ci = int.Parse(msg[2]);
                nodeAry[ai].fLen.Add(bi, ci);
                nodeAry[bi].fLen.Add(ai, ci);
            }

            int count = 0;
            for (int i = 0; i < N; i++)
            {
                //Nodeを取得
                foreach (var f in nodeAry[i].fLen.Keys) 
                {
                    //既に確認済みの組み合わせは省略(多重カウントを弾く為)
//                    if (nodeAry[i].Checked.Contains(f) || nodeAry[f].Checked.Contains(i)) continue;

                    //取得Nodeとfriendな関係を持つNodeへの
                    //迂回リンクより最短のリンクを手繰る
                    //もし直リンクより迂回リンクの方が距離が短いならばカウンタをインクリメント
                    //(幅優先検索で距離を算出するが、途中で直リンクより短距離が見えた時点で
                    // 検索を中断して良いはず＆直リンクより遠距離確定時点でQueueから捨てて良いはず)
                    LocalQueue lq = new LocalQueue(f, nodeAry[i].fLen[f],ref nodeAry, i);
                    int nNum; int tLen; HashSet<int> his;
                    while (lq.Dequeue(out nNum, out tLen, out his))
                    {
                        foreach (var nf in nodeAry[nNum].fLen.Keys)
                        {
                            if (lq.Enqueue(nf, tLen + nodeAry[nNum].fLen[nf], his) == qResult.HIT)
                            {
                                count++;
                                nodeAry[i].Checked.Add(nf);
                                break;
                            }
                        }
                    }
                }
            }
            Console.WriteLine((count / 2).ToString());
            Console.ReadLine();
        }
    }
}