思路:

首先,可以使用Dijkstra算法求出从节点1到各个节点的最短路径,得到数组d。

然后,对于每个节点i,可以考虑从节点1到节点i的路径上最后一条边的类型。如果最后一条边是宽型边,那么路径长度为d[i]。如果最后一条边是窄型边,那么路径长度为d[i]+1。因此,可以使用两个数组w和n,分别表示从节点1到节点i的最短宽型路径长度和最短窄型路径长度。

接下来,考虑如何更新数组w和n。假设当前正在处理从节点1到节点i的路径,最后一条边的类型为宽型边。那么,可以考虑从节点i出发的所有宽型边和窄型边,更新从节点1到节点j的最短宽型路径长度和最短窄型路径长度。具体地,对于每条宽型边(i, j),如果w[i]+K[i][j]<w[j],那么更新w[j]=w[i]+K[i][j]。对于每条窄型边(i, j),如果n[i]+Z[i][j]<n[j],那么更新n[j]=n[i]+Z[i][j]。最后,如果w[j]<INF(INF表示正无穷),则更新a[j]=w[j];如果n[j]<INF,则更新a[j]=n[j]+1。如果a[j]还没有被更新过,那么说明从节点1到节点j没有宽窄交替出现的路径,因此a[j]=-1。

代码实现:

const int INF = 1e9;
vector<pair<int, int>> adj[1005]; // 邻接表,存储图
int K[1005][1005], Z[1005][1005]; // 边的权值
int d[1005], w[1005], n[1005], a[1005]; // 数组
bool vis[1005];

void dijkstra(int s) {
    fill(d, d+1005, INF);
    d[s] = 0;
    priority_queue<pair<int, int>, vector<pair<int, int>>, greater<pair<int, int>>> pq;
    pq.push({0, s});
    while (!pq.empty()) {
        int u = pq.top().second; pq.pop();
        if (vis[u]) continue;
        vis[u] = true;
        for (auto [v, w] : adj[u]) {
            if (d[u] + w < d[v]) {
                d[v] = d[u] + w;
                pq.push({d[v], v});
            }
        }
    }
}

void solve() {
    int n;
    cin >> n;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cin >> K[i][j];
        }
    }
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cin >> Z[i][j];
        }
    }
    // 构建邻接表
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (K[i][j] < INF) {
                adj[i].push_back({j, K[i][j]});
            }
            if (Z[i][j] < INF) {
                adj[i].push_back({j, Z[i][j]});
            }
        }
    }
    // 使用Dijkstra算法求出从节点1到各个节点的最短路径
    dijkstra(0);
    // 初始化数组
    fill(w, w+1005, INF);
    fill(n, n+1005, INF);
    fill(a, a+1005, -1);
    // 更新数组w和n
    for (int u = 0; u < n; u++) {
        for (auto [v, w] : adj[u]) {
            if (d[u] + w == d[v]) { // 宽型边
                if (w < K[u][v]) { // 走窄型边更优
                    n[v] = min(n[v], w);
                } else {
                    w[v] = min(w[v], w);
                }
            } else if (d[u] + w + 1 == d[v]) { // 窄型边
                if (w < Z[u][v]) { // 走宽型边更优
                    w[v] = min(w[v], w+1);
                } else {
                    n[v] = min(n[v], w+1);
                }
            }
        }
    }
    // 更新数组a
    for (int i = 1; i < n; i++) {
        if (w[i] < INF) {
            a[i] = w[i];
        } else if (n[i] < INF) {
            a[i] = n[i] + 1;
        }
    }
    // 输出结果
    for (int i = 0; i < n; i++) {
        cout << a[i] << " ";
    }
    cout << endl;
}

int main() {
    int T;
    cin >> T;
    while (T--) {
        solve();
    }
    return 0;
}
c++实现有n个节点的有向图节点编号为012…n-1。图中的边只有两种类型宽型和窄型并且存在自环和平行的边。Kij表示从节点i到节点j的宽型有向边。Zij表示从节点i到节点j的窄型有向边。输出数组a长度为nai表示从节点1到节点i的宽窄交替出现的最短路径的长度。不存在这样的路径则ai=-1。

原文地址: https://www.cveoy.top/t/topic/b9cA 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录