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

题意:

有 $n \times 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}nm\log(nm) ) = O( nm (K + \frac{nm\log(nm)}{K}) )$,由此可知取 $K=\sqrt{nm \log(nm) }$ 时,时间复杂度最小,为 $O(nm\sqrt{nm\log(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=; 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[]={,,-,};
int dy[]={,,,-};
int d[maxn*maxn]; bool vis[maxn*maxn];
priority_queue< P, vector<P>, greater<P> > Q; int main()
{
ios::sync_with_stdio();
cin.tie(), cout.tie(); cin>>n>>m>>p;
K=sqrt(n*m*log2(n*m));
for(int i=,tp;i<=n;i++)
{
for(int j=;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[]) dp[v]=dist(mp(,),pos[v]);
for(int i=;i<=p;i++)
{
if(T[i].size()<=K)
{
for(auto v:T[i])
for(auto u:T[i-])
dp[v]=min(dp[v],dp[u]+dist(pos[u],pos[v]));
}
else
{
memset(d,0x3f,sizeof(d));
memset(vis,,sizeof(vis));
for(auto u:T[i-]) 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]=;
for(int k=;k<;k++)
{
if(pos[u].fi+dx[k]< || pos[u].fi+dx[k]>n) continue;
if(pos[u].se+dy[k]< || 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]+) d[v]=d[u]+, Q.push(mp(d[v],v));
}
} for(auto v:T[i]) dp[v]=d[v];
}
}
cout<<dp[ed]<<endl;
}

Codeforces 677D - Vanya and Treasure - [DP+优先队列BFS]的更多相关文章

  1. Codeforces 677D Vanya and Treasure 暴力+BFS

    链接 Codeforces 677D Vanya and Treasure 题意 n*m中有p个type,经过了任意一个 type=i 的各自才能打开 type=i+1 的钥匙,最初有type=1的钥 ...

  2. CodeForces 677D. Vanya and Treasure 枚举行列

    677D. Vanya and Treasure 题意: 给定一张n*m的图,图上每个点标有1~p的值,你初始在(1,1)点,你必须按照V:1,2,3...p的顺序走图上的点,问你如何走时间最少. 思 ...

  3. CodeForces 677D Vanya and Treasure

    $dp$,树状数组. 很明显这是一个$DAG$上的$dp$,由于边太多,暴力$dp$会超时,需要优化. 例如计算$dp[x][y]$,可以将区域分成四块,$dp[x][y]$取四块中的最小值,每一块用 ...

  4. Codeforces Round #355 (Div. 2) D. Vanya and Treasure dp+分块

    题目链接: http://codeforces.com/contest/677/problem/D 题意: 让你求最短的从start->...->1->...->2->. ...

  5. codeforces 677D D. Vanya and Treasure(二维线段树)

    题目链接: D. Vanya and Treasure time limit per test 1.5 seconds memory limit per test 256 megabytes inpu ...

  6. Codeforces Round #355 (Div. 2) D. Vanya and Treasure 分治暴力

    D. Vanya and Treasure 题目连接: http://www.codeforces.com/contest/677/problem/D Description Vanya is in ...

  7. codeforces 677D(分层图dp)

    Codeforces 677D 传送门:https://codeforces.com/contest/677/problem/D 题意: 给你一个n*m的方格图,每个点有一个权值val,现在要求你从坐 ...

  8. Codeforces 981 共同点路径覆盖树构造 BFS/DP书架&最大值

    A /*Huyyt*/ #include<bits/stdc++.h> #define mem(a,b) memset(a,b,sizeof(a)) #define pb push_bac ...

  9. 题解-CF677D Vanya and Treasure

    CF677D Vanya and Treasure 有一个 \(n\times m\) 的矩阵 \(a(1\le a_{i,j}\le p)\),求从起点 \((1,1)\) 出发依次遍历值为 \(1 ...

随机推荐

  1. InnoDB 存储引擎的主要知识点介绍

    本文转载自:Draveness,略有修改 原文链接:『浅入浅出』MySQL 和 InnoDB · 面向信仰编程 作为一名开发人员,在日常的工作中会难以避免地接触到数据库,无论是基于文件的 sqlite ...

  2. OpenCV 学习笔记 06 SIFT使用中出现版权问题error: (-213:The function/feature is not implemented)

    1 错误原因 1.1 报错全部信息: cv2.error: OpenCV(4.0.1) D:\Build\OpenCV\opencv_contrib-4.0.1\modules\xfeatures2d ...

  3. 11G新特性 -- variable size extents

    AU是asm磁盘分配的基本单元.在oracle10g中,一个AU对应一个extent(这会增加对内存的使用),因为一个大的数据库如果含有大量的默认大小的AU,会导致数据库的share pool的大量使 ...

  4. 7.翻译系列:EF 6中的继承策略(EF 6 Code-First 系列)

    原文地址:http://www.entityframeworktutorial.net/code-first/inheritance-strategy-in-code-first.aspx EF 6 ...

  5. js实现cookie跨域功能

    /** * 设置cookie方法 * @param {string} name cookie键值 * @return {*} 返回cookie值 */ function setCookie_log(c ...

  6. 网络协议TCP/IP、IPX/SPX、NETBEUI简介

    网络中不同的工作站,服务器之间能传输数据,源于协议的存在.随着网络的发展,不同的开发商开发了不同的通信方式.为了使通信成功可靠,网络中的所有主机都必须使用同一语言,不能带有方言.因而必须开发严格的标准 ...

  7. TI开发环境下载资源

    CCSV7.0 版本下载  http://processors.wiki.ti.com/index.php/Download_CCS IAR7.10 版本下载 https://www.iar.com/ ...

  8. Ubuntu下安装Solr

    1.在清华开源软件镜像站或者http://www.us.apache.org/dist/ 下载Solr的安装包,我下载的是solr-6.5.1.tgz 2.解压并移动到/usr/local目录下 3. ...

  9. make INSTALL_MOD_PATH=path_dir modules_install

    The INSTALL_MOD_PATH variable is needed to install the modules in the target root filesystem instead ...

  10. spring quartz1.8.6集群结算服务定时任务与appserver独立分开

    1.quartz集群如何处理同一个数据库,同一套sqtz表的lock问题,否则会导致打架. 思路如下: 1.com.xxx.quartz.BeanInvokingJobDetailFactoryBea ...