题目链接:https://www.luogu.com.cn/problem/P7297
解题思路:
对于每个颜色 \(c\),在第 \(c\) 层作出一条链,对于 \(1 \le i \lt n\),\((i,c)\) 和 \((i,c+1)\) 之间有一条权值为 \(1\) 的双向边。
\((i,0)\) 向 \((i, b_i)\) 连一条权值为 \(0\) 的有向边。
对于所有 \(S_{c, b_i} = 1\) 的颜色 \(c\),从 \((i,c)\) 连向 \((i, 0)\) 一条权值为 \(0\) 的有向边。
以 \((1, 0)\) 为起点 \((n, 0)\) 为终点求最短路。
示例程序(需要开 O2 优化):
#include <bits/stdc++.h> using namespace std; const int maxn = 50050; int n, K, b[maxn], dis[maxn * 55]; struct Edge { int v, w; Edge() {} Edge(int _v, int _w) { v = _v; w = _w; } }; vector<Edge> g[maxn * 55]; char color[55][55]; bool vis[maxn * 55]; struct Node { int u, dis; bool operator < (const Node& b) const { return dis > b.dis; } }; priority_queue<Node> que; int ha(int u, int k) { return k * n + u; } int main() { ios::sync_with_stdio(0); cin.tie(); cin >> n >> K; for (int i = 1; i < n; i ++) { for (int j = 1; j <= K; j ++) { g[ha(i, j)].push_back({ha(i+1, j), 1}); g[ha(i+1, j)].push_back({ha(i, j), 1}); } } for (int i = 1; i <= n; i ++) cin >> b[i]; for (int i = 1; i <= K; i ++) cin >> color[i]+1; for (int i = 1; i <= n; i ++) { g[ha(i, 0)].push_back({ha(i, b[i]), 0}); for (int j = 1; j <= K; j ++) if (color[j][b[i]] == '1') g[ha(i, j)].push_back({ha(i, 0), 0}); } memset(dis, -1, sizeof(dis)); que.push({ha(1, 0), 0}); dis[ha(1, 0)] = 0; while (!que.empty()) { Node nd = que.top(); que.pop(); int u = nd.u, d = nd.dis; if (vis[u]) continue; vis[u] = true; if (u == ha(n, 0)) break; for (auto e : g[u]) { int v = e.v, w = e.w; if (dis[v] == -1 || dis[v] > d + w) { dis[v] = d + w; que.push({v, d+w}); } } } cout << dis[ha(n, 0)] << endl; return 0; }