http://codeforces.com/problemset/problem/677/D

题目大意:

给你一个n*m的图,上面有p种钥匙(p<=n*m),每种钥匙至少有一个,期初所有为1的钥匙都是可拿的,拿到了该钥匙以后(假设该钥匙的val是v)就可以拿v+1种类的钥匙。问最后拿到第p个钥匙最少走多少步?(钥匙为p种类的只有一种)

思路:官方题解貌似是二维线段树的,不过这题可以用另外一个方法来优化。

首先假设我们目前在的颜色的c,我们要到c+1颜色的格子里面去,如果单纯的对于每种颜色c跑一次spfa的话,那么就是n*n*m*m了,所以我们分类讨论。当len(c)*len(c+1)<=n*m的时候,直接暴力就好了,反之就跑spfa。因为len(c)*len(c+1)的组数必然不多,所以肯定比每次直接跑n*m的spfa要好。

//看看会不会爆int!数组会不会少了一维!
//取物问题一定要小心先手胜利的条件
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define ALL(a) a.begin(), a.end()
#define pb push_back
#define mk make_pair
#define fi first
#define se second
const int inf = 0x3f3f3f3f;
const int maxn = + ;
int n, m, p;
int atlas[maxn][maxn];
vector<pair<int, int> > v[maxn * maxn];
int dp[maxn][maxn], dis[maxn][maxn];
bool vis[maxn][maxn];
int dx[] = {-, , , };
int dy[] = {, , , -}; int solve(){
for (int i = ; i < p; i++){
int len1 = v[i].size();
int len2 = v[i + ].size();
if (len1 * len2 <= n * m){
for (int j = ; j < len1; j++){
int jx = v[i][j].fi, jy = v[i][j].se;
for (int k = ; k < len2; k++){
int kx = v[i + ][k].fi, ky = v[i + ][k].se;
dp[kx][ky] = min(dp[kx][ky], dp[jx][jy] + abs(kx - jx) + abs(ky - jy));
}
}
}
else {
memset(dis, -, sizeof(dis));
memset(vis, false, sizeof(vis));
queue<pair<int, int> > que;
for (int j = ; j < len1; j++){
int jx = v[i][j].fi, jy = v[i][j].se;
dis[jx][jy] = dp[jx][jy];
que.push(mk(jx, jy));
vis[jx][jy] = true;
}
while (!que.empty()){
pair<int, int> u = que.front(); que.pop();
vis[u.fi][u.se] = false;
for (int j = ; j < ; j++){
int jx = u.fi + dx[j], jy = u.se + dy[j];
if (jx <= || jx > n || jy <= || jy > m) continue;
if (dis[jx][jy] == - || dis[jx][jy] > dis[u.fi][u.se] + ){
dis[jx][jy] = dis[u.fi][u.se] + ;
if (!vis[jx][jy]){
vis[jx][jy] = true;
que.push(mk(jx, jy));
}
}
}
}
for (int j = ; j < len2; j++){
int jx = v[i + ][j].fi, jy = v[i + ][j].se;
dp[jx][jy] = min(dp[jx][jy], dis[jx][jy]);
}
}
}
int px = v[p][].fi, py = v[p][].se;
return dp[px][py];
} int main(){
cin >> n >> m >> p;
for (int i = ; i <= n; i++){
for (int j = ; j <= m; j++){
int c; scanf("%d", &c);
if (c == ) dp[i][j] = i + j - ;
else dp[i][j] = inf;
v[c].pb(mk(i, j));
atlas[i][j] = c;
}
}
printf("%d\n", solve());
return ;
}

codeforces div2 677 D的更多相关文章

  1. Codeforces Round #677 (Div. 3) 题解

    Codeforces Round #677 (Div. 3) 题解 A. Boring Apartments 题目 题解 简单签到题,直接数,小于这个数的\(+10\). 代码 #include &l ...

  2. codeforces DIV2 D 最短路

    http://codeforces.com/contest/716/problem/D 题目大意:给你一些边,有权值,权值为0的表示目前该边不存在,但是可以把0修改成另外一个权值.现在,我们重新建路, ...

  3. codeforces div2.C

    C. New Year and Rating time limit per test 2 seconds memory limit per test 256 megabytes input stand ...

  4. codeforces div2 603 D. Secret Passwords(并查集)

    题目链接:https://codeforces.com/contest/1263/problem/D 题意:有n个小写字符串代表n个密码,加入存在两个密码有共同的字母,那么说这两个密码可以认为是同一个 ...

  5. codeforces div2 603 E. Editor(线段树)

    题目链接:https://codeforces.com/contest/1263/problem/E 题意:一个编译器,每次输入一些字符,R表示光标右移,L表示光标左移,然后有一些左括号(  和 右括 ...

  6. codeforces div2 603 C. Everyone is a Winner!(二分)

    题目链接:https://codeforces.com/contest/1263/problem/C 题意:给你一个数字n,求n/k有多少个不同的数 思路:首先K大于n时,n/k是0.然后k取值在1到 ...

  7. Codeforces Round #677 (Div. 3) D/1433D Districts Connection

    https://codeforces.com/contest/1433/problem/D 找两个不同权值的节点A.B连起来,所有与A不同权值的连到A上,相同的连到B上. #include<io ...

  8. Codeforces Round #677 (Div. 3) G. Reducing Delivery Cost(dijkstra算法)

    题目链接:https://codeforces.com/contest/1433/problem/G 题解 跑 \(n\) 遍 \(dijkstra\) 得到任意两点间的距离,然后枚举哪一条边权为 \ ...

  9. Codeforces Round #677 (Div. 3)【ABCDE】

    比赛链接:https://codeforces.com/contest/1433 A. Boring Apartments 题解 模拟即可. 代码 #include <bits/stdc++.h ...

随机推荐

  1. 恢复SQLSERVER被误删除的数据(转)

    恢复SQLSERVER被误删除的数据 曾经想实现Log Explorer for SQL Server的功能,利用ldf里面的日志来还原误删除的数据 这里有一篇文章做到了,不过似乎不是所有的数据类型都 ...

  2. bootsraps ch1

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name ...

  3. ubuntu server 时区设置问题解决

    1.当执行此命令的时候 ntpdate us.pool.ntp.org 出现一下错误提示 name server cannot be used: Temporary failure in name r ...

  4. HDU 5806 NanoApe Loves Sequence Ⅱ

    将大于等于m的数改为1,其余的改为0.问题转变成了有多少个区间的区间和>=k.可以枚举起点,二分第一个终点 或者尺取法. #pragma comment(linker, "/STACK ...

  5. leetcode415---字符串大数相加

    Given two non-negative numbers num1 and num2 represented as string, return the sum of num1 and num2. ...

  6. inflate的使用注意事项

    public View inflate (int resource, ViewGroup root, boolean attachToRoot) 我们在使用这个方法时,要清楚原理,下面是这个方法的文档 ...

  7. 移动端Click300毫秒点击延迟的来龙去脉(转)

    原文地址:What Exactly Is….. The 300ms Click Delay 快速响应是所有 UI 实现的重中之重.研究表明,当延迟超过 100 毫秒,用户就能感受到界面的卡顿. 然而, ...

  8. 第十四章:使用CSS3进行增强

    1.为不支持某些属性的浏览器使用polyfill:如果想弥合较弱的浏览器和较强的浏览器之间的功能差异,可以使用polyfill(通常又称作垫片),通常用js实现.但是有些较弱的浏览器运行JS的速度要慢 ...

  9. hdu_3555_Bomb(数位DP)

    题目连接:hdu_3555_Bomb 题意:和2089一样,只是数据大了点,不过道理是一样的 #include<cstdio> #include<cstring> #defin ...

  10. MC 自己平均

    using System; using System.Drawing; using System.Linq; using System.Collections; namespace PowerLang ...