題意
給你n個城市,編號爲0到n-1,然後每個城市有一隻狗,擁有pi的彈跳力,也就是可以走到相鄰的x-pi和x+pi,當然你可以走多次
現在你可以選擇當前城市的一條狗來跳,中途可以換狗,目標是你從第0只狗跳到第1只狗的最少操作
1<=n<=30000
1<=pi<=30000
2<=m<=30000
分析
一個顯而易見的小結論:每個狗只用一次,並且bfs的時候,不會走到重複的點
首先一種暴力的方法就是你可以對於每個城市預處理一下到別的城市的距離,這個是nm的,然後就是一個n^2條邊的最短路,這個方法的時間複雜度是
考慮一下優化,我們可以把邊分個組,小於等於200的一組,大於的一組,然後小於的話我們可以記錄一個vis[x][y]表示x這個點有沒有跳躍能力爲y的狗,如果當前點x,用跳躍能力爲y的狗,跳到一個城市p,同時這個城市也有跳躍能力爲y的狗,也就是說vis[p][y] = true,那麼就可以停下來
大於200的暴力跳,總的時間複雜度是
代碼
#include <bits/stdc++.h>
#define pb push_back
#define MP make_pair
using namespace std;
const int N = 30010;
const int inf = 1e9;
inline int read()
{
char ch=getchar(); int p=0; int f=1;
while(ch<'0' || ch>'9'){if(ch=='-') f=-1; ch=getchar();}
while(ch>='0' && ch<='9'){p=p*10+ch-'0'; ch=getchar();}
return p*f;
}
vector<int>g[N]; int d[N]; int s,t,n,m;
bool vis[N][202]; queue<int> q; bool v[N];
void bfs()
{
memset(d,63,sizeof(d)); d[s] = 0;
memset(v,0,sizeof(v)); v[s] = 1;
while(!q.empty()) q.pop(); q.push(s);
while(!q.empty())
{
int x = q.front(); v[x] = 0; q.pop();
for(int i=0;i<g[x].size();i++)
{
int delta = g[x][i]; int ss = 0;
for(int j=x+delta;j<n;j+=delta)
{
ss++; if(d[j] > d[x] + ss)
{
d[j] = d[x] + ss;
if(!v[j]){v[j] = 1; q.push(j);}
}
if(delta <= 200 && vis[j][delta]) break;
}
ss=0; for(int j=x-delta;j>=0;j-=delta)
{
ss++; if(d[j] > d[x] + ss)
{
d[j] = d[x] + ss;
if(!v[j]){v[j] = 1; q.push(j);}
}
if(delta <= 200 && vis[j][delta]) break;
}
}
}
if(d[t] < inf) printf("%d\n",d[t]);
else printf("-1\n");
}
int main()
{
n = read(); m = read();
for(int i=1;i<=m;i++)
{
int x = read(); int y = read();
g[x].pb(y);
if(i==1) s=x;
if(i==2) t=x;
if(y<=200) vis[x][y] = 1;
}
for(int i=1;i<=n;i++)
{
sort(g[i].begin(),g[i].end());
int len = unique(g[i].begin(),g[i].end()) - g[i].begin();
g[i].resize(len);
}
bfs();
return 0;
}