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\n", cnt);
u = 1;
do {
printf("%d ", p[u]);
u = nxt[u];
} while (u != m + 1);
}
int main() {
solve();
}