Code Jam to I/O for Women 2021
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("\n");
else printf(" ");
}
}
}