// Original C++ solution (slower):
#include <bits/stdc++.h>

using namespace std;

const int maxn = 50010;

struct node 

{

      int u,v,w;

      bool used,mark,del;

      node(int x = 0,int y = 0,int z = 0) 

	  {

        u = x;

        v = y;

        w = z;

        mark = del = used = false;

     }

     bool operator<(const node &tmp) const 

	 {

         return w < tmp.w;

     }

 }e[maxn];

 int uf[maxn],n,m,cnt;

 bool flag[maxn];

 int find(int x) {

     return uf[x] = uf[x] == x?uf[x]:find(uf[x]);

 }

 int kruskal(bool &Unique,bool first) {

     int ans = cnt = 0;

     for(int i = 0; i <= n; ++i) uf[i] = i;

     for(int i = 0; i < m; ++i) {

        if(!first && e[i].del) continue;

        int fx = find(e[i].u);

        int fy = find(e[i].v);

       if(fx != fy)

	   {

    	   	uf[fx] = fy;

            ans += e[i].w;

            if(first) 

			{

            e[i].used = true;

            if(e[i].mark) Unique = false;

            }

            if(++cnt == n-1) return ans;

	   }

     }

     return ans;

 }

 int main() {

     int u,v,w;

    // freopen("data.in","r",stdin); 

     while(~scanf("%d %d",&n,&m)) {

         for(int i = 0; i < m; ++i) {

             scanf("%d %d %d",&u,&v,&w);

             e[i] = node(u,v,w);

         }

         memset(flag,false,sizeof(flag));

         sort(e,e+m);

         for(int i = 1; i < m; ++i)

             if(e[i].w == e[i-1].w) e[i].mark = e[i-1].mark = true;

         bool Unique = true;

         int MST = kruskal(Unique,1);

         if(Unique) printf("%d %d\n",cnt,MST);

         else {

             int res1 = 0,res2 = 0;

             for(int i = 0; i < m; ++i) {

                 if(e[i].used && e[i].mark) {

                     e[i].del = true;

                     int mst = kruskal(Unique,0);

                     if(mst == MST && cnt == n-1) flag[i] = true;

                     e[i].del = false;

                 }

               if(e[i].used && !flag[i]) {

                     res1++;

                     res2 += e[i].w;

                 }

             }

             printf("%d %d\n",res1,res2);

        }

     }

     return 0;

 }

// Optimized solution to the same problem (faster):
#include<cstdio>

#include<cstring>

#include<cstdlib>

#include<cmath>

#include<algorithm>

#include<iostream>

#include<vector>

#include<queue>

#include<stack>

#include<map>

using namespace std;

typedef long long LL;

#define M(a,b) memset(a,b,sizeof(a))

struct Node

{

    int u,v,val;

    bool operator < (const Node &a) const

    {

        return val<a.val;

    }

}g[50005];

int fa[505],E[505];

int n,m,pos;

const int inf = 1<<30;

int Find(int x)

{

    return x==fa[x]?x:fa[x]=Find(fa[x]);

}

int kruscal(int x)

{

    int sum=0,edge=0;

    for (int i=1;i<=n;++i) fa[i]=i;

    for (int i=1;i<=m;++i)

    {

        if (i!=x)

        {

            int u=Find(g[i].u);

            int v=Find(g[i].v);

            if (u!=v)

            {

                sum+=g[i].val;

                fa[u]=v;

                if (!x) E[++pos]=i;

                ++edge;

            }

        }

    }

    return edge!=n-1?inf:sum;

}

int main()

{

    while(~scanf("%d%d",&n,&m))

    {

        for (int i=1;i<=m;++i)

            scanf("%d%d%d",&g[i].u,&g[i].v,&g[i].val);

        sort(g+1,g+1+m);

        pos=0;

        int tmp=kruscal(0);

        int ans=0,sum=0;

        for (int i=1;i<=pos;++i)

            if (kruscal(E[i])>tmp)

            {

                ++ans;

                sum+=g[E[i]].val;

            }

        printf("%d %d\n",ans,sum);

    }

}

// Fastest known solution for this problem: