题目链接: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. AirServer for Mac(Airplay 终端实用工具)破解版安装

    1.软件简介    AirServer 是一款 Mac 上的 AirPlay 终端,通过这款软件,利用 AirPlay 技术,iPhone 或 iPad 就可以无线连接到 Mac 上,不需要在 iPh ...

  2. 第一部分:开发前的准备-第八章 Android SDK与源码下载

    第8章 Android SDK与源码下载 如果你是新下载的SDK,请阅读一下步骤了解如何设置SDK.如果你已经下载使用过SDK,那么你应该使用AVD Manager,来更新即可. 下面是构建Andro ...

  3. Socket网络编程--网络爬虫(3)

    上一小节我们实现了从博客园的首页获取一些用户的用户名,并保存起来.接下来的这一小节我将对每个用户名构建一个用户的博客主页,然后从这个主页获取所有能获取到的网页,网页的格式现在是http://www.c ...

  4. python实现合并两个文件并打印输出

    # python实现合并两个文件并打印输出 import fileinput file_Path1 = input("请输入第一个合并文件:") file_Path2 = inpu ...

  5. 3. ELMo算法原理解析

    1. 语言模型 2. Attention Is All You Need(Transformer)算法原理解析 3. ELMo算法原理解析 4. OpenAI GPT算法原理解析 5. BERT算法原 ...

  6. 快播王欣发布匿名IM社交软件“马桶MT”

    2019年1月14日,快播王欣推出了一款匿名IM社交软件——马桶MT,它的灵感像是来自于美国的匿名分享应用Secret(已关闭). 原快播创始人王欣近日在微博预告了其新公司云歌人工智能推出一款全新社交 ...

  7. java-信息安全(六)-基于RSA理解数字签名示例

    概述 java-信息安全(四)-数据签名.数字证书 java-信息安全(五)-非对称加密算法RSA RSA工具类 使用java-信息安全(五)-非对称加密算法RSA项目中RSACoder 数字签名理解 ...

  8. JAVA常用基础知识点[继承,抽象,接口,静态,枚举,反射,泛型,多线程...]

    类的继承 Java只支持单继承,不允许多重继承- 一个子类只能有一个父类- 一个父类可以派生出多个子类这里写图片描述子类继承了父类,就继承了父类的方法和属性.在子类中,可以使用父类中定义的方法和属性, ...

  9. [IR] Huffman Coding

    为了保证:Block中,所有的叶子在所有的中间结点的前面.Static: Huffman coding Dynamic: Adaptive Huffman 一些概念 压缩指标 • Compress a ...

  10. css - 兼容适配坑点总结(。。。)

    1. transform为代表的这些css3属性一定要写-webkit-,不然低版本(目前遇到的是8)的苹果,不支持. 2. x的适配 /* x */ @media only screen and ( ...