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. yum方式安装MySQL【转】

    在CentOS7中默认安装有MariaDB,这个是MySQL的分支,但为了需要,还是要在系统中安装MySQL,而且安装完成之后可以直接覆盖掉MariaDB. 另外至2919年5月4号, 默认安装的my ...

  2. shell学习(19)- find查找命令

    Linux find命令用来在指定目录下查找文件.任何位于参数之前的字符串都将被视为欲查找的目录名.如果使用该命令时,不设置任何参数,则find命令将在当前目录下查找子目录与文件.并且将查找到的子目录 ...

  3. 【Linux】根目录命名的意义

    1./bin :获得最小的系统可操作性所需要的命令2./boot :内核和加载内核所需的文件3./dev :终端.磁盘.调制解调器等的设备项4./etc :关键的启动文件和配置文件5./home :用 ...

  4. typeid, const_cast<Type>的使用

    #include <bits/stdc++.h> using namespace std; class A { public : void Show() { cout << & ...

  5. Warning!程序员们小心被技术绑架

    通常我们说程序员需要在某个技术方向上积累到一定的厚度,要能够运用技术有效地解决实际问题.可是当程序员在某一项技术上浸淫时间长了之后,却经常会出现另外的问题,那就是:看待问题时受限于自身的技术积累. 我 ...

  6. python 嵌套列表

  7. 【vb.net机房收费系统】之没有包含要从继承的组件的已生成程序集 标签: vb.net继承 2015-05-02 15:19 1012人阅读

    在敲到组合查询这个功能的时候,需要用到窗体的继承,但是在新建继承窗体的时候,出现了错误(没有包含要从继承的组件的已生成程序集).如下图: 问题的产生:当时没怎么注意,也不知道怎么弄的,最后反正是继承上 ...

  8. 2019-8-31-dotnet-通过-WMI-获取系统信息

    title author date CreateTime categories dotnet 通过 WMI 获取系统信息 lindexi 2019-08-31 16:55:59 +0800 2019- ...

  9. CNN网络改善的方法——池化

    一个能降低卷积金字塔中特征图的空间维度,目前为止,我们通过调整步幅,将滤镜每次移动几个像素.图1 从而降低特征图的尺寸.这是降低图像采样率的一种非常有效的方法. 图1 它移除了很多信息,如果我们不采用 ...

  10. Python的unittest拓展和HTMLReport SKIP报表扩展

    C:\Python27\Lib中修改unittest内容 unittest 在init中添加Myskip代码: __all__ = ['TestResult', 'TestCase', 'TestSu ...