CF677D Vanya and Treasure(最短路)
本题容易看出分层的样子
对于i-1来更新i的答案。我们对于更新有两种选择,一种是直接枚举点对更新,一种是用spfa进行o(N*M)更新
我们发现对于两种情况的最坏复杂度情况不同,因此可以进行讨论选择使用哪一种更新、
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<int,int> pll; const int N=2e6+10; const int inf=0x3f3f3f3f; int n,m,p; int a[500][500]; vector<pll> g[N]; int dis[500][500]; int dis2[500][500]; int st[500][500]; int dx[]={-1,0,1,0}; int dy[]={0,1,0,-1}; struct node{ int cnt; int a,b; }; int cal(pll a,pll b){ return abs(a.first-b.first)+abs(a.second-b.second); } void make(int x){ int i,j; for(i=0;i<g[x].size();i++){ auto t=g[x][i]; for(j=0;j<g[x+1].size();j++){ auto tmp=g[x+1][j]; int d=cal(t,tmp); if(dis[tmp.first][tmp.second]>dis[t.first][t.second]+d){ dis[tmp.first][tmp.second]=dis[t.first][t.second]+d; } } } } void spfa(int x){ memset(dis2,0x3f,sizeof dis2); memset(st,0,sizeof st); int i,j; queue<node> q; for(i=0;i<g[x].size();i++){ auto t=g[x][i]; q.push({dis[t.first][t.second],t.first,t.second}); st[t.first][t.second]=1; dis2[t.first][t.second]=dis[t.first][t.second]; } while(q.size()){ auto t=q.front(); q.pop(); st[t.a][t.b]=0; int a=t.a,b=t.b; for(i=0;i<4;i++){ int x1=a+dx[i]; int y=b+dy[i]; if(x1&&x1<=n&&y&&y<=m){ if(dis2[x1][y]>dis2[a][b]+1){ dis2[x1][y]=dis2[a][b]+1; if(!st[x1][y]){ q.push({dis2[x1][y],x1,y}); st[x1][y]=1; } } } } } for(i=0;i<g[x+1].size();i++){ auto t=g[x+1][i]; dis[t.first][t.second]=dis2[t.first][t.second]; } } void solve(){ int i,j; for(i=0;i<(int)g[1].size();i++){ int a=g[1][i].first,b=g[1][i].second; dis[a][b]=cal(g[1][i],{1,1}); } for(i=1;i<p;i++){ if((int)g[i].size()*(int)g[i+1].size()<n*m){ make(i); } else{ spfa(i); } } } int main(){ ios::sync_with_stdio(false); cin>>n>>m>>p; int i,j; for(i=1;i<=n;i++){ for(j=1;j<=m;j++){ cin>>a[i][j]; g[a[i][j]].push_back({i,j}); } } memset(dis,0x3f,sizeof dis); solve(); auto t=g[p][0]; ll ans=dis[t.first][t.second]; cout<<ans<<endl; }
没有人不辛苦,只有人不喊疼