[NOI2005] 聪聪与可可
题目大意:给定一个无向图,聪聪在起点,可可在终点,每个时刻聪聪会沿最短路走向可可两步(如果有多条最短路走编号最小的点),然后可可会等概率向周围走或不动,求平均多少个时刻后聪聪和可可相遇, \(1\leq N,E\leq 1000\)
Solution
- \(n\)遍\(bfs\)求出点对间的最短距离
- 预处理出每个点前往每个点的下一步
- 记忆化搜索
- 状态:\(f[i][j]\)表示聪聪在\(i\)点,可可在\(j\)点,过多少时间相遇的期望
不要忘了聪聪可以走两步哟
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 1005;
int n, k, c, m, ecnt;
int head[N], dis[N][N], qwq[N][N], deg[N];
double f[N][N];
struct Edge{
int to, next;
}e[N << 1];
inline void adde(int x, int y) {
e[++ecnt].to = y;
e[ecnt].next = head[x];
head[x] = ecnt;
}
double dp(int x, int y) {
if(f[x][y] != -1.0)
return f[x][y];
if(x == y)
return f[x][y] = 0;
if(qwq[x][y] == y)
return f[x][y] = 1.0;
if(qwq[qwq[x][y]][y] == y)
return f[x][y] = 1.0;//聪聪可以走两步QAQ
f[x][y] = 0.0;
for(int i = head[y]; i; i = e[i].next) {
f[x][y] += dp(qwq[qwq[x][y]][y], e[i].to);
}
f[x][y] = (f[x][y] + dp(qwq[qwq[x][y]][y], y)) / double(deg[y] + 1) + 1;//四舍五入
return f[x][y];
}
int main() {
scanf("%d %d %d %d", &n, &k, &c, &m);
for(int i = 1, la, lb; i <= k; ++i) {
scanf("%d %d", &la, &lb);
adde(la, lb);
adde(lb, la);
deg[la]++;
deg[lb]++;
}
for(int i = 0; i <= n; ++i)
for(int j = 0; j <= n; ++j) {
f[i][j] = -1.0;
}
memset(dis, -1, sizeof(dis));
for(int i = 1; i <= n; ++i) {
dis[i][i] = 0;
queue <int> q;
q.push(i);//是push(i),不是push(1)
while(!q.empty()) {
int x = q.front();
q.pop();
for(int j = head[x]; j; j = e[j].next) {
if(dis[i][e[j].to] == -1) {
dis[i][e[j].to] = dis[i][x] + 1;
q.push(e[j].to);
}
}
}
}
memset(qwq, 0x3f, sizeof(qwq));
for(int i = 1; i <= n; ++i)
for(int j = head[i]; j; j = e[j].next) {
for(int l = 1; l <= n; ++l) {
if(dis[i][l] == dis[e[j].to][l] + 1 && qwq[i][l] > e[j].to)
qwq[i][l] = e[j].to;
}
}
printf("%.3lf", dp(c, m));
return 0;
}