time limit per test1.5 seconds

memory limit per test256 megabytes

inputstandard input

outputstandard output

Vanya is in the palace that can be represented as a grid n × m. Each room contains a single chest, an the room located in the i-th row and j-th columns contains the chest of type aij. Each chest of type x ≤ p - 1 contains a key that can open any chest of type x + 1, and all chests of type 1 are not locked. There is exactly one chest of type p and it contains a treasure.

Vanya starts in cell (1, 1) (top left corner). What is the minimum total distance Vanya has to walk in order to get the treasure? Consider the distance between cell (r1, c1) (the cell in the row r1 and column c1) and (r2, c2) is equal to |r1 - r2| + |c1 - c2|.

Input

The first line of the input contains three integers n, m and p (1 ≤ n, m ≤ 300, 1 ≤ p ≤ n·m) — the number of rows and columns in the table representing the palace and the number of different types of the chests, respectively.

Each of the following n lines contains m integers aij (1 ≤ aij ≤ p) — the types of the chests in corresponding rooms. It’s guaranteed that for each x from 1 to p there is at least one chest of this type (that is, there exists a pair of r and c, such that arc = x). Also, it’s guaranteed that there is exactly one chest of type p.

Output

Print one integer — the minimum possible total distance Vanya has to walk in order to get the treasure from the chest of type p.

Examples

input

3 4 3

2 1 1 1

1 1 1 1

2 1 1 3

output

5

input

3 3 9

1 3 5

8 9 7

4 6 2

output

22

input

3 4 12

1 2 3 4

8 7 6 5

9 10 11 12

output

11

【题解】



分成p-1步进行最短路;

即从所有i号箱子所在的位置开始进行bfs->最短路;这里最短路的终点是所有的i+1号箱子;

用一个dp[i][j]表示到(i,j)且刚好打开(i,j)的箱子所需要的最短路;

每次用得到的i号箱子到其他点的最短路来更新第i+1号箱子的dp[x]y]即可.

但是如果直接这样的话肯定不行的;

O(n*m*广搜一个n*m的图);显然会超时- -

毕竟9e4*9e4呢;

这里用到了分类讨论的思想

for (int i = 1;i <=p-1;i++)

{

—- if (pos[i].size*pos[i+1].size<=n*m)

———则直接用枚举来搞i+1号

—-else

——-用广搜更新i+1号

}

更具体点

    for (int k = 1; k <= p - 1; k++)//枚举当前的起点是啥.
{
int len1 = pos[k].size(), len2 = pos[k + 1].size();
if (len1*len2 <= n*m)//如果后一个箱子的点的数目乘当前箱子的点的数目小于等于n*m,则会比直接广搜好一点(可能)
{//要想到如果len1=2,len2=2,而n=300,m=300;那么速度不是快一点了
for (int i = 0; i <= len1 - 1; i++)
{
int a1 = pos[k][i].first, b1 = pos[k][i].second;//取出前一个点的第i号箱子的坐标
for (int j = 0; j <= len2 - 1; j++)//取出后一个箱子的第j号点的坐标
{
int a2 = pos[k + 1][j].first, b2 = pos[k + 1][j].second;
if (dis[a2][b2] > dis[a1][b1] + abs(a2 - a1) + abs(b2 - b1))//如果能够更新最优解则更新
dis[a2][b2] = dis[a1][b1] + abs(a2 - a1) + abs(b2 - b1);//相当于不是一步一步地广搜了。直接走到下一个点。
}
}
}
else
//否则就直接进行普通的广搜

为什么这样会更快?

假设p=n*m/2;(且n和m都是最大数据300)

则最坏情况每个点都只有两个(我知道p只有一个!)

则大家可以看看循环;

每一个判断都会直接进入2*2的枚举;

然后n*m/2也不大就只有45000;

2*2*45000肯定没问题的;

再坏一点

p=n*m/100

n和m依然是最大数据300

最坏情况是每个点都有100个

100*100<=90000

所以依然暴力枚举

O(100*100*p)

=O(100*100*90000/100)

=O(100*100*900)

也就是900万;

也是可以接受的;

再坏

p=n*m/1000

则最坏情况每个点最坏出现1000次

1000*1000>90000

则每个点都直接用普通的最短路搞->因为直接暴力搞显然不合适;

复杂度大概就是

O(300*300*300*300/1000)

=O(9W*900);

=8100W;

再坏

p=n*m/10000

则最坏情况每个点最坏出现10000次

10000*10000>90000

则每个点都直接用普通的最短路搞

复杂度大概就是

O(300*300*300*300/10000)

=O(9W*900);

=810W;

可以看到复杂度会变小。

所以这个分类的做法是有对算法进行优化的;

主要就是当p非常大的时候,对应每个点的出现次数会相应地减少。

这里就可以避免每次都进行最短路。

直接暴力枚举反而更快;

#include <cstdio>
#include <vector>
#include <queue>
#include <iostream>
#include <algorithm> using namespace std; const int MAXN = 310;
const int INF = 0x3f3f3f3f;
const int MAXP = 100000;
const int dx[5] = { 0,0,0,1,-1 };
const int dy[5] = { 0,1,-1,0,0 }; int n, m, p;
vector < pair<int, int> > pos[MAXP];
int dis[MAXN][MAXN],tempdis[MAXN][MAXN];
queue < pair<int, int> >dl;
bool inque[MAXN][MAXN]; void input(int &r)
{
r = 0;
char t = getchar();
while (!isdigit(t)) t = getchar();
int sign = 1;
if (t == '-')sign = -1;
while (!isdigit(t)) t = getchar();
while (isdigit(t)) r = r * 10 + t - '0', t = getchar();
r = r*sign;
} int main()
{
//freopen("F:\\rush.txt", "r", stdin);
input(n); input(m); input(p);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
dis[i][j] = INF;
for (int i = 1;i <= n;i++)
for (int j = 1; j <= m; j++)
{
int key;
input(key);
pos[key].push_back(make_pair(i, j));
if (key == 1)
dis[i][j] = abs(i - 1) + abs(j - 1);
}
for (int k = 1; k <= p - 1; k++)
{
int len1 = pos[k].size(), len2 = pos[k + 1].size();
if (len1*len2 <= n*m)
{
for (int i = 0; i <= len1 - 1; i++)
{
int a1 = pos[k][i].first, b1 = pos[k][i].second;
for (int j = 0; j <= len2 - 1; j++)
{
int a2 = pos[k + 1][j].first, b2 = pos[k + 1][j].second;
if (dis[a2][b2] > dis[a1][b1] + abs(a2 - a1) + abs(b2 - b1))
dis[a2][b2] = dis[a1][b1] + abs(a2 - a1) + abs(b2 - b1);
}
}
}
else
{
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
tempdis[i][j] = INF; for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
inque[i][j] = false; int len = pos[k].size();
for (int i = 0; i <= len - 1; i++)
{
dl.push(pos[k][i]);
int x = pos[k][i].first, y = pos[k][i].second;
inque[x][y] = true;
tempdis[x][y] = dis[x][y];
} while (!dl.empty())
{
pair <int, int> p = dl.front();
dl.pop();
inque[p.first][p.second] = false;
for (int i = 1; i <= 4; i++)
{
int x = p.first + dx[i], y = p.second + dy[i];
if (x <1 || x>n || y<1 || y>m)
continue;
if (tempdis[x][y] > tempdis[p.first][p.second] + abs(x - p.first) + abs(y - p.second))
{
tempdis[x][y] = tempdis[p.first][p.second] + abs(x - p.first) + abs(y - p.second);
if (!inque[x][y])
{
inque[x][y] = true;
dl.push(make_pair(x, y));
}
}
}
} len = pos[k + 1].size();
for (int i = 0; i <= len - 1; i++)
dis[pos[k + 1][i].first][pos[k + 1][i].second] = tempdis[pos[k + 1][i].first][pos[k + 1][i].second];
}
}
printf("%d\n", dis[pos[p][0].first][pos[p][0].second]);
return 0;
}

【12.78%】【codeforces 677D】Vanya and Treasure的更多相关文章

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

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

  2. 【 BowWow and the Timetable CodeForces - 1204A 】【思维】

    题目链接 可以发现 十进制4 对应 二进制100 十进制16 对应 二进制10000 十进制64 对应 二进制1000000 可以发现每多两个零,4的次幂就增加1. 用string读入题目给定的二进制 ...

  3. 【77.78%】【codeforces 625C】K-special Tables

    time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standa ...

  4. [原创] 【2014.12.02更新网盘链接】基于EasySysprep4.1的 Windows 7 x86/x64 『视频』封装

    [原创] [2014.12.02更新网盘链接]基于EasySysprep4.1的 Windows 7 x86/x64 『视频』封装 joinlidong 发表于 2014-11-29 14:25:50 ...

  5. 【中途相遇法】【STL】BAPC2014 K Key to Knowledge (Codeforces GYM 100526)

    题目链接: http://codeforces.com/gym/100526 http://acm.hunnu.edu.cn/online/?action=problem&type=show& ...

  6. 【codeforces 515C】Drazil and Factorial

    [题目链接]:http://codeforces.com/contest/515/problem/C [题意] 定义f(n)=n这个数各个位置上的数的阶乘的乘积; 给你a; 让你另外求一个不含0和1的 ...

  7. 【codeforces 758D】Ability To Convert

    [题目链接]:http://codeforces.com/contest/758/problem/D [题意] 给你一个n进制的数k; 问你它可能的最小的十进制数是多少; [题解] 从右往左; 获取数 ...

  8. 【codeforces 798C】Mike and gcd problem

    [题目链接]:http://codeforces.com/contest/798/problem/C [题意] 给你n个数字; 要求你进行若干次操作; 每次操作对第i和第i+1个位置的数字进行; 将 ...

  9. 【codeforces 793C】Mice problem

    [题目链接]:http://codeforces.com/contest/793/problem/C [题意] 给你每个点x轴移动速度,y轴移动速度; 问你有没有某个时刻,所有的点都"严格& ...

随机推荐

  1. SDUT-3375_数据结构实验之查找三:树的种类统计

    数据结构实验之查找三:树的种类统计 Time Limit: 400 ms Memory Limit: 65536 KiB Problem Description 随着卫星成像技术的应用,自然资源研究机 ...

  2. android GUI 流程记录

    ViewRootImpl 与 wms ViewRootImple里的 WindowSeesion是WindowManagerService的proxy, 通过这个句柄来调用WMS的功能而W是 wms用 ...

  3. php中括号定义数组

    php5.3及之前的版本是不支持中括号定义数组的.5.4之后支持. 错误信息是,不识别“[”

  4. 错误信息:FATAL: No bootable medium found! System halted.

    一.解决方法 先上1张图,显示的错误信息 再上2张图,幸好在之前安装了XP系统,不然还真不好解决.从图中可以看出WIN-XP和Linux系统安装好之后的差异,Linux的的存储信息上显示“第二通道没有 ...

  5. uva 10739【基础(区间)dp】

    Uva 10739 题意:给定字符串,可以增加.删除.修改任意字符,问最少经过多少次操作使字符串回文. 题解:定义dp[l][r]表示把从l到r的子串Sl...Sr变成回文串需要操作的最少次数.字符可 ...

  6. MaxCompute如何对SQL查询结果实现分页获取

    由于MaxCompute SQL本身不提供类似数据库的select * from table limit x offset y的分页查询逻辑.但是有很多用户希望在一定场景下能够使用获取类似数据库分页的 ...

  7. 在浏览器中打开php文件时,是Linux中的哪个用户执行的?

    https://segmentfault.com/q/1010000002541340 如题,这样我就可以针对这个用户设置权限了.而且这个用户是怎么关联上的,怎么查看? 解答一: .是执行 PHP 指 ...

  8. [软考]之软件过程模型I 标签: 总结软考 2015-10-24 11:58 863人阅读 评论(35) 收藏

    做软考题的时候经常碰到软件工程的题,因为这些题有的很相近,容易混淆,所以在这里总结归纳一下. 软件过程模型: 瀑布模型: 瀑布模型是将软件生存周期中的各个活动规定为依线性顺序连接的若干阶段的模型,包括 ...

  9. Python 官方文档:入门教程

    https://pythoncaff.com/docs/tutorial/3.7.0 官方入门教程,从这里开始你的 Python 之旅,将长久维护 基础信息 翻译说明 关于本教程 已完成 正文 1. ...

  10. oracle函数 extract(c1 from d1)

    [功能]:日期/时间d1中,参数(c1)的值 [参数]:d1日期型(date)/日期时间型(timestamp),c1为字符型(参数) [参数表]:c1对应的参数表详见示例 [返回]:字符 [示例] ...