/*
求次短路 方法: 求出最短路 枚举每一条边 temp = d1[e.from]+d2[e.to]+e.dist; 找到次短路
要注意的是 遇到 x x这种点对 不一定是输出“?” 可能有x ->y y ->x这种情况
*/
#include<cstdio>
#include<cstring>#include<vector>
#include<queue>
#define INF 1<<29
using namespace std;
int n,m,d1[110],d2[110],minp,di[110][110],p[110];
struct Edge
{
int from,to,dist;
};
struct Node
{
int u,w;
bool operator < (const Node &a) const
{
return w>a.w;
}
};
vector<Edge> edges;
vector<int> G[110];
int add(int x,int y,int z)
{
di[x][y] = z;
edges.push_back((Edge)
{
x,y,z
});
int l = edges.size();
G[x].push_back(l-1);
}
int MSP(int s,int t,int *d)
{
for(int i = 0; i < n; i++)
d[i] = INF;
d[s] = 0;
bool vis[110];
memset(vis,0,sizeof(vis));
priority_queue<Node> q;
while(!q.empty())
q.pop();
q.push((Node)
{
s,0
});
while(!q.empty())
{
Node a = q.top();
q.pop();
int u = a.u;
if(vis[u]) continue;
vis[u] = 1;
//if(u==t) break;
for(int i = 0; i < G[u].size(); i++)
{
Edge &e = edges[G[u][i]];
int v = e.to;
//printf("%d %d %d/..\n",u,v,d[u]);
if(d[v]>d[u]+e.dist)
{
d[v]=d[u]+e.dist;
p[v] = u;
q.push((Node)
{
v,d[v]
});
}
}
}
minp=d[t];
}
int main()
{
int a,b,c,t,count=1;
while(scanf("%d%d",&n,&m)==2)
{
memset(di,0,sizeof(di));
edges.clear();
for(int i = 0; i <= n; i++)
G[i].clear();
for(int i = 0; i < m; i++)
{
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
add(b,a,c);
}
scanf("%d",&t);
printf("Set #%d\n",count++);
while(t--)
{
memset(d1,0,sizeof(d1));
memset(d2,0,sizeof(d2));
scanf("%d %d",&a,&b);
if((a<0)||b>=n)
{
puts("?");
continue;
}
MSP(a,b,d1);
MSP(b,a,d2);
if(minp>=INF)
{
puts("?");
continue;
}
int ans = INF;
for(int i = 0;i<edges.size() ; i++)
{
Edge e = edges[i];
int temp = d1[e.from]+d2[e.to]+e.dist;
if(temp>minp)
{
ans = min(ans,temp);
}
}
if(ans<INF&&ans>0)
printf("%d\n",ans);
else puts("?");
}
}
return 0;
}