题目链接: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. 迷你音乐播放器v1.0正式上线!

    迷你音乐播放器V1.0正式上线! 版本介绍: 1.随机播放切换开关(通过点击专辑图片) 2.通过拖动歌曲名及艺术家名调整歌曲播放进度 3.手机浏览访问支持熄屏播放 4.暂不支持在线搜索功能 快来一起分 ...

  2. 使用EF操作不同数据库(以SQLite为例)

    最近一直在和数据库作对. 从安卓平台上给了我个SQLite数据库,要求程序能够读取不同的文件.由于字段实在太多,不愿意直接使用原来直接读取datatable的方式来做,手动写映射太痛苦...于是想起来 ...

  3. Benchmark Web App 性能瓶颈分析与性能测试工具的使用方法总结

    主要分为以下几个要素的指标: Disk IO . CPU . mem . Net . MySQL Web性能测试工具: 客户端 服务器端: 服务器性能测试工具: 服务器性能瓶颈分析工具: ab, si ...

  4. linux(mac) 编译安装MySQL

    Reference: https://blog.csdn.net/Tzhennan/article/details/80565235 官方下载地址:  https://dev.mysql.com/do ...

  5. [转]bootstrap table 动态列数

    原文地址:https://my.oschina.net/u/2356355/blog/1595563 据说bootstrap table非常好用,从入门教程中了解到它的以下主要功能: 由于固定表头意味 ...

  6. 【iCore4 双核心板_ARM】例程一:ARM驱动三色LED

    实验原理: 通过STM32的三个GPIO驱动一个三色LED,引脚PB2接红色LED(ARM_LEDR), 引脚PA9接蓝色LED(ARM_LEDB),引脚PA10接绿色LED(ARM_LEDG),   ...

  7. 初识Spring Security

    本文参考或者转自:http://haohaoxuexi.iteye.com/blog/2154299 1.新建Spring Security配置文件spring-security.xml:<?x ...

  8. Manager升职了

    公司去年从每年七月份公布officer升职改成了每年四月份公布. 早上收到大头发给全公司的邮件,赫然发现Manager升了一级到VP,虽然是金融公司,但我司的VP好像会比银行多一点点福利,比如额外假期 ...

  9. Angular4学习笔记(五)- 数据绑定、响应式编程和管道

    概念 Angular中的数据绑定指的是同一组件中控制器文件(.ts)与视图文件(.html)之间的数据传递. 分类 流向 单向绑定 它的意思是要么是ts文件为html文件赋值,要么相反. ts-> ...

  10. 二叉树转换成森林&amp;森林变成二叉树

    一,树转换成二叉树 1,将全部兄弟结点连起来; 2,保留第一个兄弟结点与父节点的连接,断开其它兄弟结点与父节点的连接,然后以根节点为轴依照顺时针方向旋转45度 watermark/2/text/aHR ...