#include <iostream>
#include <queue>
#include <vector>
#include <cstring>
#include <stdio.h>
using namespace std;

#define pb push_back
#define ll long long

#define MaxN 10010
#define MaxM 100010

struct edge {
    ll len;
    int to, rb;

    edge() {}
    edge( int _to, ll _len, int _rb ) { to = _to; len = _len; rb = _rb; }
};

struct StructHeap {
    ll tot;
    int to, rb;
    bool preko;

    StructHeap() {}
    StructHeap( ll _tot, int _to, int _rb, bool _preko ) { tot = _tot; to = _to; rb = _rb; preko = _preko; }

    bool operator < (const StructHeap &b ) const {
        if ( tot == b.tot ) return !preko;
        return tot > b.tot;
    }
};

int n,m;
int na,nb;
vector<edge> a[MaxN];
int od,to;
ll len;

bool mark1[MaxM];
bool mark2[MaxM];
bool mark[MaxN];

int ret;

void Dijkstra1()
{

    priority_queue< StructHeap > heap;
    while ( !heap.empty() ) heap.pop();
    memset( mark, 0, sizeof(mark));
    memset(mark1, 0, sizeof(mark1));

    mark[na] = true;
    for (int i = 0; i < a[ na ].size(); i++)
        heap.push( StructHeap( a[na][i].len, a[na][i].to, a[na][i].rb, a[na][i].to==nb ) );

    StructHeap p;
    while ( !heap.empty() ) {
        p = heap.top();
        heap.pop();
        if ( mark[p.to] ) continue;

        mark1[ p.rb ] = true;
        mark[p.to] = true;

        for (int i = 0; i < a[ p.to ].size(); i++)
            heap.push( StructHeap( p.tot+a[ p.to ][i].len, a[ p.to ][i].to, a[ p.to ][i].rb, p.preko || a[ p.to ][i].to == nb ) );
    }

}

void Dijkstra2()
{

    priority_queue< StructHeap > heap;
    while ( !heap.empty() ) heap.pop();
    memset( mark, 0, sizeof(mark));
    memset(mark2, 0, sizeof(mark2));

    mark[nb] = true;
    for (int i = 0; i < a[ nb ].size(); i++)
        heap.push( StructHeap( a[nb][i].len, a[nb][i].to, a[nb][i].rb, a[nb][i].to==na ) );

    StructHeap p;
    while ( !heap.empty() ) {
        p = heap.top();
        heap.pop();
        if ( mark[p.to] ) continue;

        mark2[ p.rb ] = true;
        mark[p.to] = true;

        for (int i = 0; i < a[ p.to ].size(); i++)
            heap.push( StructHeap( p.tot+a[p.to][i].len, a[ p.to ][i].to, a[ p.to ][i].rb, p.preko || a[ p.to ][i].to == na ) );
    }

}

int main()
{

    freopen("nishtel.in","r",stdin);
    freopen("nishtel.out","w",stdout);

    scanf("%d%d%d%d",&n,&m,&na,&nb);
    na--; nb--;

    for (int i = 0; i < m; i++) {
        scanf("%d%d%lld",&od,&to,&len);
        od--; to--;

        a[od].pb( edge( to, len, i ) );
    }

    Dijkstra1();
    Dijkstra2();

    /*for (int i = 0; i < m; i++) {
        printf("%d %d %d\n",i,mark1[i],mark2[i]);
    }*/

    ret = 0;
    for (int i = 0; i < m; i++)
       if ( !mark1[i] && !mark2[i] ) ret++;

    printf("%d\n",ret);

    fclose(stdin);
    fclose(stdout);

    return 0;

}
