• Codeforces 677D


    题目链接:http://codeforces.com/problemset/problem/677/D

    题意:

    有 $n imes m$ 的网格,每个网格上有一个棋子,棋子种类为 $t[i][j]$,棋子的种类数为 $p$。

    现在出发点为 $(1,1)$,必须按照种类 $1 sim p$ 进行移动,即从种类 $x$ 的棋子出发,下一个目标必须是 $x+1$ 才行,直到走到种类为 $p$ 的棋子就终止。求最短路径。

    题解:

    我们先把棋子按照种类分组,分成 $p$ 组。

    $dp[i][j]$ 表示到达目前这个棋子的最短路,那么转移方程为 $dp[i][j] = min(dp[i][j],dp[x][y]+|x-i|+|y-j|)$,其中 $(x,y)$ 为上一组中所有棋子的坐标。

    然后要是直接暴力的状态转移的话,是要TLE的,考虑进行优化。

    考虑一个界限 $K$,假设当前组为 $T[i]$,上一组为 $T[i-1]$,

    那么当 $T[i].size le K$ 时,我们就用继续用上面的暴力动态转移,那么对于所有的“上一组”点数加起来不会差过 $nm$,因此总时间复杂度 $O(K cdot nm)$;

    如果 $T[i].size > K$,我们在网格上进行多源点的优先队列BFS(或者说优先队列dijkstra),源点是所有的 $T[i-1]$ 组内的点,搜出到所有 $T[i]$ 组内的点的最短距离,这样BFS最多跑一遍所有网格,时间复杂度 $O(nm log(nm))$;由于这样的组数目不会超过 $frac{nm}{K}$ 个,所以总时间复杂度为 $O(frac{nm}{K} nm log(nm) )$。

    这样一来,两种加起来的总时间复杂度就是 $O(Knm+frac{nm}{K}nmlog(nm) ) = O( nm (K + frac{nmlog(nm)}{K}) )$,由此可知取 $K=sqrt{nm log(nm) }$ 时,时间复杂度最小,为 $O(nmsqrt{nmlog(nm)})$。

    AC代码:

    #include<bits/stdc++.h>
    #define idx(x,y) ((x-1)*m+y)
    #define mp(x,y) make_pair(x,y)
    #define fi first
    #define se second
    using namespace std;
    typedef pair<int,int> P;
    
    const int INF=0x3f3f3f3f;
    const int maxn=305;
    
    int n,m,p,ed,K;
    P pos[maxn*maxn];
    vector<int> T[maxn*maxn];
    
    int dp[maxn*maxn];
    int dist(const P& u,const P& v) {
        return abs(u.fi-v.fi)+abs(u.se-v.se);
    }
    
    int dx[4]={1,0,-1,0};
    int dy[4]={0,1,0,-1};
    int d[maxn*maxn]; bool vis[maxn*maxn];
    priority_queue< P, vector<P>, greater<P> > Q;
    
    int main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0), cout.tie(0);
    
        cin>>n>>m>>p;
        K=sqrt(n*m*log2(n*m));
        for(int i=1,tp;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                cin>>tp;
                T[tp].push_back(idx(i,j));
                pos[idx(i,j)]=mp(i,j);
                if(tp==p) ed=idx(i,j);
            }
        }
    
        memset(dp,0x3f,sizeof(dp));
        for(auto v:T[1]) dp[v]=dist(mp(1,1),pos[v]);
        for(int i=2;i<=p;i++)
        {
            if(T[i].size()<=K)
            {
                for(auto v:T[i])
                    for(auto u:T[i-1])
                        dp[v]=min(dp[v],dp[u]+dist(pos[u],pos[v]));
            }
            else
            {
                memset(d,0x3f,sizeof(d));
                memset(vis,0,sizeof(vis));
                for(auto u:T[i-1]) d[u]=dp[u], Q.push(mp(d[u],u));
                while(Q.size())
                {
                    int u=Q.top().se; Q.pop();
                    if(vis[u]) continue;
                    vis[u]=1;
                    for(int k=0;k<4;k++)
                    {
                        if(pos[u].fi+dx[k]<1 || pos[u].fi+dx[k]>n) continue;
                        if(pos[u].se+dy[k]<1 || pos[u].se+dy[k]>n) continue;
                        int v=idx(pos[u].fi+dx[k],pos[u].se+dy[k]);
                        if(vis[v]) continue;
                        if(d[v]>d[u]+1) d[v]=d[u]+1, Q.push(mp(d[v],v));
                    }
                }
    
                for(auto v:T[i]) dp[v]=d[v];
            }
        }
        cout<<dp[ed]<<endl;
    }
  • 相关阅读:
    老板也是一个工种,也是一种技能
    用上了ReSharper
    《钟馗伏魔:雪妖魔灵》另类解读
    内部培训-流程图培训
    未来价值是把信息从网上拿下来,而不是放上
    一个人的电影
    2015清明节假期纪实
    十年魔戒
    天使基金资金预期使用表
    项目过程中各阶段应交付的文档
  • 原文地址:https://www.cnblogs.com/dilthey/p/10461665.html
Copyright © 2020-2023  润新知