题目链接:http://poj.org/problem?id=3114
题意:
有几个城市连通,如果几个城市互相连通,则他们传送信件不需要时间,否则就需要一些时间传送,现在问你某两个城市之间传送信件最少需要多长时间
题解:
最短路+强连通分量,两个模板直接搞定。
代码:
// memset 只能赋值 -1 和 0,其余用 fill()
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int size = 505, size2 = 505*505, inf = 1 << 26;
struct edges {
int to, next;
} ed[size2];
int n, m;
int dfn[size], low[size], head[size], stack[size], instack[size], sccno[size], w[size][size];
int mp[size][size];
int dis[size], vis[size];// 最短路数组
int cnt = 0, qcnt = 0, top = 0, scccnt = 0;
void add(int u, int v) {
ed[cnt].to = v;
ed[cnt].next = head[u];
head[u] = cnt ++;
}
void init() {
cnt = qcnt = scccnt = top = 0;
memset(ed, 0, sizeof(ed));
memset(dfn, 0, sizeof(dfn));
memset(low, 0, sizeof(low));
memset(head, -1, sizeof(head));
memset(stack, 0, sizeof(stack));
memset(instack, 0, sizeof(instack));
memset(instack, 0, sizeof(instack));
memset(sccno, 0, sizeof(sccno));
memset(vis, 0, sizeof(vis));
for ( int i = 0; i <= n; i ++ ) for ( int j = 0; j <= n; j ++ ) w[i][j] = inf;
for ( int i = 0; i <= n; i ++ ) for ( int j = 0; j <= n; j ++ ) mp[i][j] = inf;
}
void Tarjan(int x) {
dfn[x] = low[x] = ++qcnt;
instack[x] = 1;
stack[++top] = x;
for ( int i = head[x]; i != -1; i = ed[i].next ) {
int y = ed[i].to;
if(!dfn[y]) { // 检查是否被访问过
Tarjan(y);
low[x] = min(low[x], low[y]);
} else if(instack[y]) {
low[x] = min(low[x], low[y]);
//== dfn[i]
}
}
if(dfn[x] == low[x]) {
int temp;
scccnt ++;
do {
temp = stack[top --];
instack[temp] = 0;
sccno[temp] = scccnt;
} while( temp != x );
}
}
void spfa(int s) {
for ( int i = 0; i <= n; i ++) dis[i] = inf;
dis[s] = 0;
queue<int> q;
q.push(s);
vis[s] = 1;
while(!q.empty()) {
int t = q.front(); q.pop();
vis[t] = 0;
for ( int i = 1; i <= scccnt; i ++ ) {
if(dis[i] > dis[t]+mp[t][i]) {
dis[i] = dis[t]+mp[t][i];
if(!vis[i]) {
q.push(i);
vis[i] = 1;
}
}
}
}
}
int main() {
// freopen("3114.in", "r", stdin);
while( scanf("%d %d", &n, &m), n ) {
init();
int a, b, c;
for ( int i = 1; i <= m; i ++ ) {
scanf("%d %d %d", &a, &b, &c);
add(a, b);
w[a][b] = min(w[a][b], c);
}
for ( int i = 1; i <= n; i ++ ) {
if(!dfn[i]) Tarjan(i);
}
for ( int i = 0; i <= n; i ++ ) mp[i][i] = 0;
for ( int i = 1; i <= n; i ++ ) {
for ( int j = 1; j <= n; j ++ ) {
if(i != j && sccno[i] != sccno[j] && w[i][j] != inf) {
mp[sccno[i]][sccno[j]] = min(mp[sccno[i]][sccno[j]], w[i][j]);
}
}
}
int k;
scanf("%d", &k);
for ( int i = 0; i < k; i ++ ) {
int a, b;
scanf("%d %d", &a, &b);
if(sccno[a] == sccno[b]) { // 属于一个强连通分量
puts("0");
} else {
spfa(sccno[a]);
if(dis[sccno[b]] < inf) printf("%d\n", dis[sccno[b]]);
else puts("Nao e possivel entregar a carta");
}
}
puts("");
}
return 0;
}