#include<bits/stdc++.h>
#define INF 1e9
#define llINF 1e18
#define MOD 1000000007
#define pb push_back
#define mp make_pair 
#define F first
#define S second
#define ll long long
#define ull unsigned long long
#define vi vector<ll>
#define vvi vector<vi>
#define DBG_N(hoge) cerr<<" "<<(hoge)<<endl;
#define DBG cerr<<"!"<<endl;
#define BITLE(n) (1LL<<((ll)n))
#define BITCNT(n) (__builtin_popcountll(n))
#define SUBS(s,f,t) ((s).substr((f)-1,(t)-(f)+1))
#define ALL(a) (a).begin(),(a).end()
using namespace std;
struct edge{
  ll from,to,cost;
  bool operator < (const edge &HOGE)const{return cost<HOGE.cost;};
};
struct UF
{
  vector<int> par;
  vector<int> sz;
  vector<int> rank;
  UF(int n):par(n),sz(n),rank(n){
    for(int i = 0; i < n; i++){
      par[i] = i;sz[i] = 1;rank[i] = 0;
    }
  }
  int find(int x) {
    if (par[x] == x) return x;
    else return par[x] = find(par[x]);
  }
  void merge(int x, int y) {
    x = find(x); y = find(y);
    if (x == y) return;
    if(rank[x] < rank[y]){
      par[x] = y;
      sz[y] += sz[x];
    }
    else{
      par[y] = x;
      sz[x] += sz[y];
      if(rank[x] == rank[y])rank[x]++;
    }
  }
  bool same(int x, int y) { return find(x) == find(y); }
  int size(int n){return sz[find(n)];}
};

ll n,m;
vector<edge>E;
vi po;
ll kruskal(int hoge){
  UF uf(n);
  ll ret = 0;
  ll cnt=0;
  for(int i=0;i<m;i++){
    if(hoge == i)continue;
    if(uf.same(E[i].from,E[i].to))continue;
    uf.merge(E[i].from,E[i].to);
    if(hoge == -1)
      po.pb(i);
    ret+=E[i].cost;
    cnt++;
  }

  if(cnt != n-1)return llINF;
  return ret;
}
int main(){
  cin.tie(0);
  ios::sync_with_stdio(false);
  cin>>n>>m;
  for(int i=0;i<m;i++){
    ll from,to,cost;
    cin>>from>>to>>cost;
    E.pb({from-1,to-1,cost});
  }
  sort(ALL(E));
  ll c = kruskal(-1);
  ll ans=0;
  ll anscnt=0;
  for(int i=0;i<po.size();i++){
    if(c!=kruskal(po[i])){anscnt++;ans+=E[po[i]].cost;}
  }
  cout<<anscnt<<" "<<ans<<endl;
  return 0;
}

