CodeForces-1204C Anna, Svyatoslav and Maps 图论,最短路,双向链表

CodeForces-1204C Anna, Svyatoslav and Maps 图论,最短路,双向链表

题意

给你一张(n) 个点的有向图和一个长度为(m) 的路径(P_1,P_2.......P_m)

求一个最短的子序列(Q_1,Q_2.......Q_k) ,使得(P_1 = Q_1,P_m = Q_k)

且路径(P_1,P_2......P_m) 为按顺序访问 (Q) 每个点的一条最短路

[m leq 10^6,n leq 100 ]

分析

相当于给出一个路径要你进行删点操作,什么点可以删去?注意到一个很好的性质,如果已经算出了多源最短路

如果有

[dis[pre[i]][i] + dis[i][nxt[i]] = dis[pre[i]][nxt[i]] ]

就表明(i) 这个点在再短路上,存在是没必要的,可以删去。

因此可以操作一个双向链表模拟删除操作

代码

int w[105][105];
int p[maxn];
char s[maxn];
int a[maxn], pre[maxn], nxt[maxn];



void solve() {
    int n = readint();
    for (int i = 0; i <= 100; i++) for (int j = 0; j <= 100; j++) w[i][j] = 100000;
    for (int i = 1; i <= n; i++) {
        scanf("%s", s + 1);
        for (int j = 1; j <= n; j++)
            if (s[j] == '1') w[i][j] = 1;
    }
    for (int k = 1; k <= n; k++)
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                if (i == k || j == k || i == j) continue;
                else  w[i][j] = min(w[i][j], w[i][k] + w[k][j]);
    int m = readint();
    for (int i = 1; i <= m; i++) p[i] = readint(), pre[i] = i - 1, nxt[i] = i + 1;
    int u, preu, nxtu;
    int cnt = m;
    u = nxt[1];
    while (u != m) {
        preu = p[pre[u]], nxtu = p[nxt[u]];
        if (w[preu][p[u]] + w[p[u]][nxtu] == w[preu][nxtu]) {
            nxt[pre[u]] = nxt[u];
            pre[nxt[u]] = pre[u];
            cnt--;
        }
        u = nxt[u];
    }
    printf("%d
", cnt);
    u = 1;
    do {
        printf("%d ", p[u]);
        u = nxt[u];
    } while (u != m + 1);
}



int main() {
    solve();
}
原文地址:https://www.cnblogs.com/hznumqf/p/13583376.html