[题解] BYVoid 魔兽世界模拟赛 Stage.1 埃雷萨拉斯寻宝 (缩点最短路)
- 传送门 -
https://www.byvoid.com/zhs/blog/byvoid-wow-stage-1
const int N = 55;
const int NN = 2505;
const int M = 20000;
int MAP[N][N], C[N][N], DIS[NN];
int P[NN], VIS[NN];
int HD[NN], TO[M], NXT[M];
int X[4] = {0,0,1,-1};
int Y[4] = {1,-1,0,0};
int n, p, h, s, t, sz;
queue
void add(int x, int y) {
TO[sz] = y; NXT[sz] = HD[x]; HD[x] = sz++;
TO[sz] = x; NXT[sz] = HD[y]; HD[y] = sz++;
}
void dfs(int x, int y, int d) {
if (MAP[x][y] != d) {
if (!VIS[MAP[x][y]]) {
VIS[MAP[x][y]] = 1;
add(d, MAP[x][y]);
} //缩点
return;
}
C[x][y] = 1;
for (int i = 0; i < 4; ++i) {
int xx = x + X[i], yy = y + Y[i];
if (xx > 0 && xx <= n && yy > 0 && yy <= n)
if (C[xx][yy] == 0)
dfs(xx, yy, d);
}
}
void spfa() {
memset(DIS, 0x3f, sizeof (DIS));
DIS[s] = 0;
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop();
VIS[u] = 0;
for (int i = HD[u]; i != -1; i = NXT[i]) {
int v = TO[i];
if (DIS[v] > DIS[u] + P[v]) {
DIS[v] = DIS[u] + P[v];
if (!VIS[v]) {
VIS[v] = 1;
q.push(v);
}
}
}
}
if (DIS[t] >= h) printf("NO\n");
else printf("%d\n", h - DIS[t]);
}
int main() {
freopen("eldrethalas.in","r",stdin);
freopen("eldrethalas.out","w",stdout);
memset(HD, -1, sizeof (HD));
scanf("%d%d%d", &n, &p, &h);
for (int i = 1; i <= p; ++i)
scanf("%d", &P[i]);
t = p + 1; //缩完点后点的编号为 1 到 p
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j) {
scanf("%d", &MAP[i][j]);
}
for (int i = 1; i <= n; ++i) {
if (!VIS[MAP[1][i]]) {
VIS[MAP[1][i]] = 1;
add(s, MAP[1][i]);
}
}
memset(VIS, 0, sizeof (VIS));
for (int i = 1; i <= n; ++i) {
if (!VIS[MAP[n][i]]) {
VIS[MAP[n][i]] = 1;
add(MAP[n][i], t);
}
} //连起点终点
memset(VIS, 0, sizeof (VIS));
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
if (!C[i][j]) {
dfs(i, j, MAP[i][j]);
memset(VIS, 0, sizeof (VIS));
}
spfa();
return 0;
}
[1]: http://www.cnblogs.com/Anding-16/p/7435266.html
[2]: http://www.cnblogs.com/Anding-16/p/7434599.html