Code Jam to I/O for Women 2021
C Introductions Organization 最短路 + 思维
题目大意:
给你 (n) 个经理,编号从 (1) 到 (n) ,(m) 个非经理,假设 (b) 和 (c) 不认识,但是他们都认识经理 (a) ,那么在 (1s) 内,经理 (a) 可以介绍 (b) 和 (c) 认识,有 (q) 此询问,每次询问 (x) 和 (y) ,问最少经过多少 (s) 他们会相互认识。
题解:
首先求出 (x) 和 (y) 的最短路 (ans) (注意这个最短路上除了起点和终点应该只包括经理的点)
我是希望他们两个的最短路越短越好,所以每一次介绍我希望是缩短的最短路上的点。
假设最短路是 (x - a - b - c - d - e - y)
那么第一秒应该是 (x-a-b) 使得变成 (x - b) ,同时 (c - d - e) 变成 (c - e)
不会有比这个更优的情况了,假设有 (a - d) 直接认识的,那么说明有一条路是 (x - a - ? - d)
那么这条才是最短路,而不是 (x - a - b - c - d)
所以其实求出最短路之后,不断的分成三个一组,进行合并即可。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 110;
int w[maxn][maxn],dis[maxn],n,m,p;
char s[maxn];
queue<int>que;
int bfs(int sx,int sy) {
while (!que.empty()) que.pop();
memset(dis, 0, sizeof(dis));
dis[sx] = 1;
que.push(sx);
while (!que.empty()) {
int u = que.front();
que.pop();
if (u == sy) return dis[u];
if (w[u][sy]) return dis[u] + 1;
for (int j = 1; j <= n; j++) {
if (dis[j]) continue;
if (!w[u][j]) continue;
dis[j] = dis[u] + 1;
que.push(j);
}
}
return -1;
}
int main() {
int T;
scanf("%d", &T);
for (int cas = 1; cas <= T; cas++) {
scanf("%d%d%d", &n, &m, &p);
for (int i = 1; i <= n + m; i++) {
scanf("%s", s + 1);
for (int j = 1; j <= n + m; j++) {
if (s[j] == 'Y') w[i][j] = 1;
else w[i][j] = 0;
}
}
printf("Case #%d: ", cas);
for (int i = 1; i <= p; i++) {
int sx, sy;
scanf("%d%d", &sx, &sy);
int res = bfs(sx, sy), ans = 0;
while (res >= 3) {
res = res / 3 * 2 + res % 3, ans++;
}
if (res < 0) ans = -1;
printf("%d", ans);
if (i == p) printf("
");
else printf(" ");
}
}
}