题目链接: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;
}