题目链接: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. R中统计假设检验总结(一)

    先PS一个:考虑到这次的题目本身的特点 尝试下把说明性内容都直接作为备注写在语句中 另外用于说明的部分例子参考了我的教授Guy Yollin在Financial Data Analysis and M ...

  2. 10.翻译系列:EF 6中的Fluent API配置【EF 6 Code-First系列】

    原文链接:https://www.entityframeworktutorial.net/code-first/fluent-api-in-code-first.aspx EF 6 Code-Firs ...

  3. Github忽略keil工程生成的链接、编译等文件

    *.bak *.ddk *.edk *.lst *.lnp *.mpf *.mpj *.obj *.omf *.plg *.rpt *.tmp *.__i *.crf *.o *.d *.axf *. ...

  4. 关于烦躁的网页编码问题utf-8,gb2312。终于自己实践了一遍

    俗话说实践是检验真理的唯一标准,的确如此. 自己一直比较懒,虽然觉得大牛应该一个记事本全部搞定,但自己还是喜欢用Dw或者Vs写好网页的架构,因为总觉得用notepad还要自己导入声明,而gVim还没有 ...

  5. python文件的基础操作

    import os print(,'-')) print(os.getcwd()) print(,'-')) print(os.listdir()) print(,'-')) print(os.lis ...

  6. 动软 生成 linq相关DAO

    第一步:新建自定义模板 <#@ template language="c#" HostSpecific="True" #> <#@ outpu ...

  7. 【WPF】点击滑动条(Slider),移动滑块(Tick)到鼠标点击的位置

    问题:点击Slider控件时,滑块会自动跳到滑动条的最边缘位置,无法跳到鼠标点击的位置上. 办法:给Slider控件设置属性IsMoveToPointEnabled="True"即 ...

  8. 【网络编程】——ne-snmp开发实例1

    net-snmp扩展有多种方式,在此只介绍两种——动态库扩展,静态库扩展. 在做net-snmp开发之前,首先确定net-snmp相关的软件是否安装. rpm -qa | grep snmp net- ...

  9. spring 手动添加 bean 到容器,例子 :多数据源配置

    package com.thunisoft.spsjsb.config.db.decrypt; import com.alibaba.druid.pool.DruidDataSource; impor ...

  10. json转 PostMan bulk Edit application/x-www-form-urlencoded 需要的格式

    {?\n\s*"([^"]+)"\s*:\s*"?([^,"]+)"?\s*,?}? $1:$2\n PostMan需要的格式. json转 ...