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;
}
View Code

 

posted @ 2020-10-11 20:24  朝暮不思  阅读(190)  评论(0编辑  收藏  举报