您的位置:首页 > 其它

CJOJ 1217 【HAOI2005】路由选择问题

2017-04-12 19:28 357 查看
【HAOI2005】路由选择问题

Description

X城有一个含有N个节点的通信网络,在通信中,我们往往关心信息从一个节点I传输到节点J的最短路径。遗憾的是,由于种种原因,线路中总有一些节点会出故障,因此在传输中要避开故障节点。

任务一:在己知故障节点的情况下,求避开这些故障节点,从节点I到节点J的最短路径S0。

任务二:在不考虑故障节点的情况下,求从节点I到节点J的最短路径S1、第二最短路径S2。

Input

第1行: N I J (节点个数 起始节点 目标节点)

第2—N+1行: Sk1 Sk2…SkN (节点K到节点J的距离为SkJ K=1,2,……,N)

最后一行: P T1 T2……Tp (故障节点的个数及编号)

Output

S0 S1 S2 (S1<=S2 从节点I到节点J至少有两条不同路径)

Sample Input

5 1 5

0 10 5 0 0

10 0 0 6 20

5 0 0 30 35

0 6 30 0 6

0 20 35 6 0

1 2

Sample Output

40 22 30

Hint

【约束条件】

(1)N<=50 N个节点的编号为1,2,…,N

(2)Skj为整数,Skj<=100,(K,J=1,2…,N 若Skj=0表示节点K到节点J没线路)

(3)P<=5  

样例解释:



Source

[HAOI2005]

图论,最短路,次短路

Solution

对于前面两个询问,直接spfa即可(同时记录最短路径),对于第三个询问,每一次删掉最短路径中的一条边,然后再spfa找到删过边后的最短边,即为次短边

Code

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
#include <map>
#include <vector>
#include <queue>
#define L 60
#define LL long long
using namespace std;

struct node {
int nxt, to, v;
} e[L << 1];
int n, st, se, P, p[L], minx = 2000000009, v, cnt, bj1 = 0, bj2 = 0, dis[L], head[L], pre[L];
bool vis[L], in[L];
queue <int> q;

inline void add(int a, int b, int c) {
e[++cnt].nxt = head[a], e[cnt].to = b, e[cnt].v = c, head[a] = cnt;
}

inline void spfa(int pd) {
while (!q.empty()) q.pop();
if (pd == 1) memset(pre, 0, sizeof(pre));
for (int i = 1; i <= n; ++i) in[i] = false, dis[i] = 2000000009;
dis[st] = 0, in[st] = true, pre[st] = -1, q.push(st);
while (!q.empty()) {
int x = q.front();
q.pop(), in[x] = 0;
for (int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if ((x == bj1 && y == bj2) || (x == bj2 && y == bj1)) continue;
if (vis[y]) continue;
if (dis[y] > dis[x] + e[i].v) {
dis[y] = dis[x] + e[i].v;
if (pd) pre[y] = x;
if (!in[y]) in[y] = 1, q.push(y);
}
}
}
}

int main(){
freopen("CJOJ1217.in", "r", stdin);
freopen("CJOJ1217.out", "w", stdout);
scanf("%d %d %d", &n, &st, &se);
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j) {
scanf("%d", &v);
if (v == 0) continue;
else add(i, j, v);
}
scanf("%d" ,&P);
for (int i = 1; i <= P; ++i) scanf("%d", &p[i]), vis[p[i]] = 1;
spfa(1), printf("%d ", dis[se]);
memset(vis, 0, sizeof(vis));
spfa(1), printf("%d ", dis[se]);
v = se;
while (pre[v] != -1) {
bj1 = v, bj2 = pre[v];
spfa(0);
minx = min(minx, dis[se]);
v = pre[v];
pre[st] = -1;
}
printf("%d", minx);
return 0;
}


Summary

注意找次短边的方式
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  图论