问题描述
这天, 小明在玩迷宫游戏。
迷宫为一个 n×n 的网格图, 小明可以在格子中移动, 左上角为 (1,1), 右下角 (n, n)为终点。迷宫中除了可以向上下左右四个方向移动一格以外, 还有 m 个双向传送门可以使用, 传送门可以连接两个任意格子。
假如小明处在格子(x1,y1), 同时有一个传送门连接了格子(x1,y1) 和 (x2,y2), 那么小明既可以花费 1 的步数向上下左右四个方向之一走一格 (不能越过边界), 也可以花费 1 的步数通过传送门走到格子 (x2,y2) 去。
而对于同一个迷宫, 小明每次进入的初始格子是在这n×n 个格子中均匀随 机的 (当然运气好可以直接随机到终点), 他想知道从初始格子走到终点的最短 步数的期望值是多少。
输入格式
输入共 1+m 行, 第一行为两个正整数 n,m 。
后面 mm 行, 每行四个正整数 xi1,yi1,xi2,yi2 表示第 i 个传送门连接的两个格子坐标。
输出格式
输出共一行, 一个浮点数表示答案 (请保留两位小数)。
样例输入
2 1 1 1 2 2样例输出
0.75
反向搜索 只要搜一次就行
另外本题不标记 因为传送门会使之前的结果不一定是最优的。增加了空间复杂度。
- #include<bits/stdc++.h>
- using namespace std;
- #define int long long
- #define fp(i,a,b) for(int i=a;i<=b;++i)
- #define PII pair<int,int>
- const int N=2e3+10;
- const int mod=1e9+7;
- const double eps=1e-5;
- typedef double db;
- int dx[]={0,0,1,-1};
- int dy[]={1,-1,0,0};
- int n,m;
- int dist[N][N];
- vector<PII>door[N][N];
- bool is_door[N][N];
- void bfs()
- {
- memset(dist,0x3f,sizeof dist);
- dist[n][n]=0;
- queue<PII>q;
- q.push({n,n});
-
- while(q.size())
- {
- auto t=q.front();
- q.pop();
-
- for(int p=0;p<4;p++)
- {
- int X=dx[p]+t.first,Y=dy[p]+t.second;
- if(X<1||X>n||Y<1||Y>n) continue;
-
- if(dist[X][Y]>dist[t.first][t.second]+1)
- {
- dist[X][Y]=dist[t.first][t.second]+1;
- q.push({X,Y});
- }
- if(is_door[t.first][t.second])//如果当前点可以使用传送门
- {
- //因为是反向搜图,可以多对一
- for(auto s:door[t.first][t.second])
- {
- //取出里面的点
- if(dist[s.first][s.second]>dist[t.first][t.second]+1)
- {
- dist[s.first][s.second]=dist[t.first][t.second]+1;
- q.push({s.first,s.second});
- }
- }
- }
-
- }
- }
- }
- signed main()
- {
- cin>>n>>m;
-
- for(int i=1;i<=m;i++)
- {
- int a,b,c,d;
- cin>>a>>b>>c>>d;
- door[a][b].push_back({c,d});
- door[c][d].push_back({a,b});
- is_door[a][b]=is_door[c][d]=true;
- }
- bfs();
- int sum=0;
- for(int i=1;i<=n;i++)
- {
- for(int j=1;j<=n;j++)
- {
- sum+=dist[i][j];
- }
- }
- cout<<fixed<<setprecision(2)<<1.0*sum/(n*n)<<"\n";
-
- return 0;
- }
-