Description
间谍在战争时期想要传递一份信件回国,信件可以在邮局之间传递,这种传递是单向的并且有耗时,如果两个邮局在同一个国家的话,那么信件在它们之间传递可以立即完成,而判断两个邮局是否属于同一个国家的依据就是发出的信件可以互相到达,现给出多次查询,每次查询从一个点传递信件到另一个点最快需要多久
Input
多组用例,每组用例第一行为两个整数n和m表示点数和边数,之后m行每行三个整数a,b,c表示从a传递到b需要耗时c,然后是一整数k表示查询次数,之后k行每行两个整数a和b表示查询从a传递信件到b最快需要多久,以0 0结束输入
(1<=n<=500,0<=m<=n^2,0<=k<=100)
Output
对于每组用例,输出a到b传递信件的最快时间,如果信件无法传递则输出”Nao e possivel entregar a carta”,每组用例输出后输出一空行
Sample Input
4 5
1 2 5
2 1 10
3 4 8
4 3 7
2 3 6
5
1 2
1 3
1 4
4 3
4 1
3 3
1 2 10
2 3 1
3 2 1
3
1 3
3 1
3 2
0 0
Sample Output
0
6
6
0
Nao e possivel entregar a carta
10
Nao e possivel entregar a carta
0
Solution
建完图后tarjan求强连通分量缩点,那么处于同一强连通分量中的两点之间互传耗时为0,而对于不在同一强连通分量中的两点的查询,对缩完的点建新图,边权为两个分量中点之间边的最小边权,对于每次查询,以起点做一次spfa求到终点的最短路即可
Code
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<stack>
using namespace std;
#define maxn 555
#define INF 0x3f3f3f3f
struct Edge
{
int to,next,c;
}edge[maxn*maxn];
vector<int>g[maxn];
stack<int>st;
int n,m,scc,index;
int head[maxn],tot,low[maxn],dfn[maxn],instack[maxn],fa[maxn];
void init()//初始化
{
tot=scc=index=0;
while(!st.empty())st.pop();
for(int i=0;i<maxn;i++)g[i].clear();
memset(head,-1,sizeof(head));
memset(dfn,0,sizeof(dfn));
memset(instack,0,sizeof(instack));
memset(low,0,sizeof(low));
}
void add(int u,int v)//建u到v的单向边
{
g[u].push_back(v);
}
void add_edge(int u,int v,int c)
{
edge[tot].to=v;
edge[tot].c=c;
edge[tot].next=head[u];
head[u]=tot++;
}
void tarjan(int u)//求强联通分量
{
dfn[u]=low[u]=++index;
instack[u]=1;
st.push(u);
int v,size=g[u].size();
for(int i=0;i<size;i++)
{
v=g[u][i];
if(!dfn[v])
{
tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(instack[v])
low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u])
{
scc++;
do
{
v=st.top();
st.pop();
fa[v]=scc;
instack[v]=0;
}while(v!=u);
}
}
void solve()
{
for(int i=1;i<=n;i++)
if(!dfn[i])
tarjan(i);
}
int spfa(int s,int e)
{
bool vis[maxn];
int dis[maxn];
queue<int>que;
for(int i=1;i<=scc;i++)vis[i]=0,dis[i]=INF;
dis[s]=0,vis[s]=1;
que.push(s);
while(!que.empty())
{
int u=que.front();
que.pop();
vis[u]=0;
for(int i=head[u];i!=-1;i=edge[i].next)
{
int v=edge[i].to,c=edge[i].c;
if(dis[v]>dis[u]+c)
{
dis[v]=dis[u]+c;
if(!vis[v])
{
vis[v]=1;
que.push(v);
}
}
}
}
return dis[e];
}
int k,cost[maxn][maxn],d[maxn][maxn];
int main()
{
while(~scanf("%d%d",&n,&m),n)
{
init();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cost[i][j]=INF;
while(m--)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
cost[a][b]=min(cost[a][b],c),add(a,b);
}
solve();
for(int i=1;i<=scc;i++)
for(int j=1;j<=scc;j++)
d[i][j]=INF;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(fa[i]!=fa[j])
d[fa[i]][fa[j]]=min(d[fa[i]][fa[j]],cost[i][j]);
tot=0;
memset(head,-1,sizeof(head));
for(int i=1;i<=scc;i++)
for(int j=1;j<=scc;j++)
if(d[i][j]!=INF)add_edge(i,j,d[i][j]);
scanf("%d",&k);
while(k--)
{
int a,b;
scanf("%d%d",&a,&b);
a=fa[a],b=fa[b];
if(a==b)printf("0\n");
else
{
int ans=spfa(a,b);
if(ans!=INF)printf("%d\n",ans);
else printf("Nao e possivel entregar a carta\n");
}
}
printf("\n");
}
return 0;
}