#include <bits/stdc++.h>
#include <bits/extc++.h>
#define ll long long
#define int ll
#define INF LLONG_MAX
using namespace std;
using namespace __gnu_pbds;
const int maxn=4e3;
tree <ll,null_type,less<ll>,rb_tree_tag,tree_order_statistics_node_update> TREE ;
inline int read(){
int ret=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
while(isdigit(ch)){ret=ret*10+ch-'0';ch=getchar();}
return ret*f;
}
ll n,m,aans;
int closest[maxn],lowcost[maxn];
int G[maxn][maxn];
inline ll prim(int s){
for(int i=1;i<=maxn;i++){
lowcost[i]=INF;
}
for(int i=1;i<=maxn;i++){
closest[i]=0;
}
closest[s]=-1;
lowcost[s]=0;
ll num=0,ans=0,e=s;
while(num<n-1){
int micost=INF,miedge=-1;
for(int i=1;i<=n;i++){
if(closest[i]!=-1){
int temp=G[e][i];
if(temp==0) continue;
if(temp<lowcost[i])
lowcost[i]=temp,closest[i]=e;
if(lowcost[i]<micost)
micost=lowcost[miedge=i];
}
}
num++;
closest[e=miedge]=-1;
ans=std::max(micost,ans);
}
return ans;
}
signed main(){
n=read(),m=read();
srand(time(0));
for(int i=1;i<=m;i++){
int u=read(),v=read(),w=read();
if(G[u][v]!=0) G[u][v]=std::min(w,G[u][v]),G[v][u]=G[u][v];
else G[u][v]=w,G[v][u]=w;
}
aans=prim(1);
std::cout<<n-1<<" "<<aans<<"\n";
return 0;
}