最短路+搜索
本题考察搜索的奇技淫巧,让我口胡一下
先floyd把最短路跑出来。维护an[i]表示在i处且不在任何车上,到b的最少次数,那么最终答案是an[a]。正推无法更新答案,因为可能出现循环更新,我们考虑从终点逆推更新答案。
初始设an[b] = 0。然后我们O(n^2)地暴力枚举每一条车的线路+暴力枚举每一个站点,O(n)dfs来找出所有an[i] = 1的站点。然后继续暴力算出所有an[i] = 2的站点。。。。。。因为每次更新必然至少能更新一个点,所以有an[i] <= n。因此时间复杂度O(n^4)。
记忆化搜索不记忆化也能过。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 105
using namespace std;
namespace runzhe2000
{
const int INF = 1000000000;
int n, m, a, b, d[N][N], timer, ecnt, vis[N], cnt[N], buscnt, s[N], t[N], must[N][N], an[N], last[N], f[N];
struct edge{int next, to;}e[N*N];
void addedge(int a, int b){e[++ecnt] = (edge){last[a], b}; last[a] = ecnt;}
int dfs(int x, int y)
{
int tmp = -1;
for(int i = last[x]; i; i = e[i].next)
{
int j = e[i].to;
if(d[x][j] + d[j][y] == d[x][y] && d[x][j] < INF) tmp = max(tmp, dfs(j,y));
}
if(tmp == -1) tmp = INF;
tmp = min(tmp, an[x] + 1); return tmp;
}
void main()
{
scanf("%d%d%d%d",&n,&m,&a,&b);
memset(d,63,sizeof(d));
for(int i = 1, u, v; i <= m; i++)
{
scanf("%d%d",&u,&v);
d[u][v] = 1; addedge(u, v);
}
for(int i = 1; i <= n; i++) d[i][i] = 0;
for(int k = 1; k <= n; k++) for(int i = 1; i <= n; i++) for(int j = 1; j <= n; j++) d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
scanf("%d",&buscnt);
for(int i = 1; i <= buscnt; i++)
{
scanf("%d%d",&s[i],&t[i]);
memset(cnt,0,sizeof(cnt));
for(int j = 1; j <= n; j++)
if(d[s[i]][j] + d[j][t[i]] == d[s[i]][t[i]] && d[s[i]][t[i]] < INF)
cnt[d[s[i]][j]]++;
for(int j = 1; j <= n; j++)
if(d[s[i]][j] + d[j][t[i]] == d[s[i]][t[i]] && d[s[i]][t[i]] < INF && cnt[d[s[i]][j]] == 1)
must[i][j] = 1;
}
memset(an,63,sizeof(an));
for(an[b] = 0; ; )
{
bool ok = 1;
for(int i = 1; i <= buscnt; i++)
for(int j = 1; j <= n; j++) if(must[i][j])
{
++timer;
int ans = dfs(j, t[i]);
if(ans < an[j]) an[j] = ans, ok = 0;
}
if(ok) break;
}
printf("%d\n",an[a] < INF ? an[a] : -1);
}
}
int main()
{
runzhe2000::main();
}