codeforces div2 677 D
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的更多相关文章
- Codeforces Round #677 (Div. 3) 题解
Codeforces Round #677 (Div. 3) 题解 A. Boring Apartments 题目 题解 简单签到题,直接数,小于这个数的\(+10\). 代码 #include &l ...
- codeforces DIV2 D 最短路
http://codeforces.com/contest/716/problem/D 题目大意:给你一些边,有权值,权值为0的表示目前该边不存在,但是可以把0修改成另外一个权值.现在,我们重新建路, ...
- codeforces div2.C
C. New Year and Rating time limit per test 2 seconds memory limit per test 256 megabytes input stand ...
- codeforces div2 603 D. Secret Passwords(并查集)
题目链接:https://codeforces.com/contest/1263/problem/D 题意:有n个小写字符串代表n个密码,加入存在两个密码有共同的字母,那么说这两个密码可以认为是同一个 ...
- codeforces div2 603 E. Editor(线段树)
题目链接:https://codeforces.com/contest/1263/problem/E 题意:一个编译器,每次输入一些字符,R表示光标右移,L表示光标左移,然后有一些左括号( 和 右括 ...
- 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到 ...
- Codeforces Round #677 (Div. 3) D/1433D Districts Connection
https://codeforces.com/contest/1433/problem/D 找两个不同权值的节点A.B连起来,所有与A不同权值的连到A上,相同的连到B上. #include<io ...
- Codeforces Round #677 (Div. 3) G. Reducing Delivery Cost(dijkstra算法)
题目链接:https://codeforces.com/contest/1433/problem/G 题解 跑 \(n\) 遍 \(dijkstra\) 得到任意两点间的距离,然后枚举哪一条边权为 \ ...
- Codeforces Round #677 (Div. 3)【ABCDE】
比赛链接:https://codeforces.com/contest/1433 A. Boring Apartments 题解 模拟即可. 代码 #include <bits/stdc++.h ...
随机推荐
- iOS学习笔记(01) - 泛型
决定新开一坑,在不断学习的同时分享自己的学习历程给大家,既是对自己学习的记录,又希望能对大家提供些微的帮助. 这一篇文章主要来介绍泛型的意义.使用与声明方法等. 1.泛型:限制类型 1.1.泛型使用场 ...
- java启动子进程以及进程通信
1.利用进程的管道通信传输流 2.子进程没有控制台,正常测试的时候也是没办法看到子进程的输出的,需要传到主线程 3.测试主进程传参给子进程再传回来 4.父进程启动子进程只要执行runtime.exec ...
- POJ 3347 Kadj Squares (线段覆盖)
题目大意:给你几个正方形的边长,正方一个顶点在x轴上然后边与x轴的夹角为45度,每个正方形都是紧贴的,问从上面看能看的正方形的编号 题目思路:线段覆盖,边长乘上2防止产生小数,求出每个正方形与x轴平行 ...
- java基础算法题
为了提高自己的代码能力和算法能力,我决定每天学习一道算法题,吸收前辈思想. [程序1] TestRabbit.java 题目:古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三 ...
- ZUFE OJ 2289 God Wang II
Description 这个世界太无聊了,于是God Wang想出了新的运算符号$,对于两个数x,y来说x$y的值等于x和y各个位置上的数字乘积之和,没有的位按0来算 比如说123$321=1*3+2 ...
- c++ lower_bound upper_bound
lower_bound, first greater than or equal to upper_bound, first strickly greater
- eclipse关联源码的方法
1.在项目的libs目录下,新建一个android-support-v4.jar.properties文件 2.打开android-support-v4.jar.properties,编辑. 输入源码 ...
- js获取tr,td内容并排序
如题 <!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.o ...
- vs调试有时能进去后台,有时不能进去
前两天做项目时,遇到调试时有时候能进后台,有时候直接就弹出运行结果,反复查找原因,最后发现,原来是页面输出缓存的原因,我在web页面用到了< OutputCache Duration=" ...
- Windows下动态库的编译以及调用
1.MFC下生成动态库 1>显式调用 在.cpp文件里添加接口函数 int sum(int a,int b) { return a + b; } int sub(int a,int b) { r ...