题目链接: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. 自己动手编译Linux内核

    2008年04月27日       整理了一下Linux内核编译的方法,原始内核版本为Linux-2.4.20.8,新内核版本为Linux-2.4.22,其它内核版本编译方法类似.     一 准备工 ...

  2. 苹果产品时间发布表统计(iPhone、iPad),以及32位和64位机的说明

    之前因为某些原因,需要对apple家族的手机和pad产品做一个上市时间排序,以及分析分别是哪种CPU机型 总结如下: iPad家族: 1.iPad   - 2010.1.27发布 2.iPad 2   ...

  3. JVM源码分析之Object.wait/notify实现(转载)

    最简单的东西,往往包含了最复杂的实现,因为需要为上层的存在提供一个稳定的基础,Object作为java中所有对象的基类,其存在的价值不言而喻,其中wait和notify方法的实现多线程协作提供了保证. ...

  4. ORA-214 signalled during: ALTER DATABASE MOUNT 问题

    数据库服务器移动了位置,后来再连其数据库发现提示无法连接,大致为“无法为所有新实例创建连接...”,查看alert日志发现有如下错误: starting up 1 dispatcher(s) for ...

  5. Effective Java 第三版——36. 使用EnumSet替代位属性

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  6. Socket网络编程--简单Web服务器(3)

    上一小节已经实现了浏览器发送请求,然后服务器给出应答信息,然后浏览器显示出服务器发送过来的网页.一切看起来都是那么的美好.这一小节就准备实现可以根据地址栏url的不同来返回指定的网页.目前还不考虑带参 ...

  7. SourceInsight: sourceInsight4.0 修改默认字体

    快捷键 Alt + Y

  8. python bottle框架 解决跨域问题的正确方式

    经查询,网上有几种说法 https://www.cnblogs.com/EmptyFS/p/6138923.html 我首先查到的就是这个,我采用了文中所说的修改源码的方式, 但是经测试发现,修改源码 ...

  9. 【转】css3实现文字闪烁,改变透明度

    <style> @-webkit-keyframes shake{ 0%{ opacity: 1; } 50%{ opacity: 0.5; } 100%{ opacity: 1; } } ...

  10. 登录tomcat服务器首页直接跳转到项目

    原文:https://www.cnblogs.com/xwdreamer/p/3489996.html 需求: 客户觉得每次输入http://10.138.16.232:8080/abc/ 比较烦,他 ...