#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
//快读
unsigned int read() {
int x=0;
char ch=getchar();
while(ch<‘0‘||ch>‘9‘) ch=getchar();
while(ch>=‘0‘&&ch<=‘9‘) x*=10,x+=ch-‘0‘,ch=getchar();
return x;
}
//变量声明
int N,M,L[3005];
vector<int> protect[3005];
//图
int head[3005],ver[70005],edge[70005],Next[70005],tot=0;
void add(int u,int v,int weight) {
ver[++tot]=v;
edge[tot]=weight;
Next[tot]=head[u];
head[u]=tot;
}
//dijkstra算法
int dis1[3005],dis2[3005],vis[3005];
priority_queue<pair<int,int> > q;
void dijkstra() {
memset(dis1,0x3f,sizeof(dis1));
memset(vis,0,sizeof(vis));
dis1[1]=0;
q.push(make_pair(0,1));
while(!q.empty()) {
int now=q.top().second;
q.pop();
if(vis[now]) continue;
vis[now]=1;
//dis1的处理
for(int i=head[now];i;i=Next[i]) {
int to=ver[i],w=edge[i];
if(dis1[to]>max(dis1[now],dis2[now])+w) {
dis1[to]=max(dis1[now],dis2[now])+w;
if(!L[to]) q.push(make_pair(-max(dis1[to],dis2[to]),to));
}
}
//dis2的处理
for(int i=0;i<protect[now].size();i++) {
int target=protect[now][i];
L[target]--;
dis2[target]=max(max(dis1[now],dis2[now]),dis2[target]);
if(!L[target]) q.push(make_pair(-max(dis1[target],dis2[target]),target));
}
}
}
//执行
int main() {
N=read();M=read();
for(int i=1;i<=M;i++) {
int u_i=read(),v_i=read(),w_i=read();
if(u_i!=v_i) add(u_i,v_i,w_i);
}
for(int i=1;i<=N;i++) {
L[i]=read();
for(int j=1;j<=L[i];j++) {
int num=read();
protect[num].push_back(i);
}
}
dijkstra();
int ans=max(dis1[N],dis2[N]);
printf("%d\n",ans);
return 0;
}