# include <iostream>
# include <vector>
# include <cstdio>
# include <cstring>
# include <set>

using namespace std;

const int MaxN = 10000;
const int MaxM = 100000;

struct Edge {
       int to;
       int idx;
       int cost;
       
       Edge( int a = 0, int b = 0, int c = 0 )
             : to( a ), idx( b ), cost( c ) { }
};

int dist[MaxN];

struct El {
       int node;
       
       El( int a = 0 )
           : node( a ) { }
       
       bool operator<( const El& other ) const {
            if ( dist[node] != dist[other.node] )
               return dist[node] < dist[other.node];
            return node < other.node;
       }
};

set< El > s;

int n;
int m;
int a;
int b;
vector< Edge > g[MaxN];

bool noNeed[2][MaxM];
vector< int > need[2][MaxN];

bool mark[MaxM];

void Dijkstra( int t ) {
     s.clear();
     for ( int i = 0; i < n; i++ ) need[t][i].clear();
     for ( int i = 0; i < n; i++ ) dist[i] = 987654321;
     
     s.insert( El( ( t == 0 ) ? a : b ) );
     dist[ ( t == 0 ? a : b ) ] = 0;
     
     while ( !s.empty() ) {
           int node = (*s.begin()).node;
           s.erase( s.begin() );
           
           for ( vector< Edge >::iterator it = g[node].begin(); it != g[node].end(); it++ )
               if ( dist[it->to] > dist[node] + it->cost ) {
                    for ( vector< int >::iterator it2 = need[t][it->to].begin(); it2 != need[t][it->to].end(); it2++ )
                        noNeed[t][*it2] = 1;
                    need[t][it->to].clear();
                    need[t][it->to].push_back( it->idx );
                    
                    if ( s.count( El( it->to ) ) )
                       s.erase( s.find( El( it->to ) ) );
                    dist[it->to] = dist[node] + it->cost;
                    s.insert( El( it->to ) );
               } else if ( dist[it->to] < dist[node] + it->cost )
                    noNeed[t][it->idx] = 1;
               else need[t][it->to].push_back( it->idx );
     }
}

int main() {
    freopen( "nishtel.in", "r", stdin );
    freopen( "nishtel.out", "w", stdout );
    
    for ( int i = 0; i < n; i++ ) g[i].clear();
    scanf( "%d%d%d%d", &n, &m, &a, &b );
    a--;
    b--;
    for ( int i = 0; i < m; i++ ) {
        int x, y, z;
        scanf( "%d%d%d", &x, &y, &z );
        g[x - 1].push_back( Edge( y - 1, i, z ) );
    }
    
    memset( noNeed[0], 0, sizeof( noNeed[0] ) );
    memset( noNeed[1], 0, sizeof( noNeed[1] ) );
    Dijkstra( 0 );
    Dijkstra( 1 );
    
    int res = 0;
    for ( int i = 0; i < m; i++ )
        if ( noNeed[0][i] && noNeed[1][i] )
           res++;
           
    for ( int i = 0; i < n; i++ ) {
        if ( i == a || i == b ) continue;
        
        memset( mark, 0, sizeof( mark ) );
        for ( vector< int >::iterator it = need[0][i].begin(); it != need[0][i].end(); it++ )
            mark[*it] = 1;
            
        int cnt = 0;
        for ( vector< int >::iterator it = need[1][i].begin(); it != need[1][i].end(); it++ )
            if ( mark[*it] ) cnt++;
            
        res += need[0][i].size() + need[1][i].size() - ( cnt > 0 ? cnt - 1 : 0 ) - 2;
    }
    
    res += need[0][b].size() - 1;
    res += need[1][a].size() - 1;
    
    printf( "%d\n", res );
    
    return 0;
}
