#include "bits/stdc++.h"

using namespace std;

typedef long long ll;
typedef pair<int,int> P;
const double EPS = 1e-12;
const int INF = numeric_limits<int>::max()/2;
const int MOD = 1e9+7;

struct Edge{
    int from, to,cost;
    Edge(int from, int to,int cost): from(from), to(to), cost(cost){}
};
typedef vector<Edge> Edges;
typedef vector<Edges> Graph;

bool operator < (const Edge &e, const Edge &f){
    return e.cost < f.cost;
}

struct UF {
	vector<int> data;
	UF(int size) : data(size, -1) { }
	bool unite(int x, int y) {
		x = root(x); y = root(y);
		if (x != y) {
			if (data[y] < data[x]) swap(x, y);
			data[x] += data[y]; data[y] = x;
		}
		return x != y;
	}
	bool find(int x, int y) {
		return root(x) == root(y);
	}
	int root(int x) {
		return data[x] < 0 ? x : data[x] = root(data[x]);
	}
	int size(int x) {
		return -data[root(x)];
	}
    void init(int size){
        for(int i=0;i<size;i++) data[i]=-1;
    }
};

int main(){
    cin.tie(0);
    ios::sync_with_stdio(false);

    int n,m;cin>>n>>m;
    Edges es;
    for(int i=0;i<m;i++){
        int st,gt,cost;
        cin>>st>>gt>>cost;st--;gt--;
        es.push_back(Edge(st,gt,cost));
    }
    sort(es.begin(),es.end());
    UF uf(n);
    int mcost=0;
    Edges used;
    for(int i=0;i<m;i++){
        Edge e=es[i];
        if(!uf.find(e.from,e.to)){
            mcost+=e.cost;
            uf.unite(e.from,e.to);
            used.push_back(e);
        }
    }
    int res=0,sum=0;
    for(int i=0;i<n-1;i++){
        uf.init(n);
        int tmp=0;
        for(int j=0;j<m;j++){
            Edge e=es[j];
            if(e.from==used[i].from && e.to==used[i].to) continue;
            if(!uf.find(e.from,e.to)){
                tmp+=e.cost;
                uf.unite(e.from,e.to);
            }
        }
        if(mcost!=tmp){
            res++;
            sum+=used[i].cost;
        }
    }
    cout<<res<<" "<<sum<<endl;
}
