题目链接:http://codeforces.com/contest/821/problem/D
题意:n*m地图,有k个位置是点亮的,有4个移动方向,每次可以移动到相邻的点亮位置,每次站在初始被点亮某个位置,暂时使某行或该某列全部点亮,花费为1,下一次使用时,上一次暂时点亮被熄灭
题解:显然只要知道如果两点相邻直接相连然后就是极限情况,什么情况之下是两点是连不到一起的。如果x轴与y轴的相差大于2是连不到一起的。
具体画一下图就知道了。然后就跑一遍dij+优先队列就行了或者spfa也行。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <cmath>
#define inf 0X3f3f3f3f
using namespace std;
const int M = 1e4 + 10;
typedef long long ll;
ll dis[M];
bool vis[M];
int n , m , k , flag;
struct TnT {
int x , y;
}T[M];
struct qnode {
int v;
ll c;
qnode(int v , ll c):v(v) , c(c) {}
bool operator <(const qnode &r) const{
return c > r.c;
}
};
void dij() {
priority_queue<qnode>q;
memset(vis , false , sizeof(vis));
q.push(qnode(1 , 0));
dis[1] = 0;
while(!q.empty()) {
int u = q.top().v;
q.pop();
if(vis[u]) continue;
vis[u] = true;
for(int i = 1 ; i <= k ; i++) {
int v = i;
int dx = abs(T[u].x - T[v].x) , dy = abs(T[u].y - T[v].y);
if(dx + dy == 1) {
if(!flag && T[v].x == n && T[v].y == m) {
if(dis[v] > dis[u] + 1 && !vis[v]) {
dis[v] = dis[u] + 1;
q.push(qnode(v , dis[v]));
}
}
else {
if(dis[v] > dis[u] && !vis[v]) {
dis[v] = dis[u];
q.push(qnode(v , dis[v]));
}
}
}
else {
if(dx <= 2 || dy <= 2) {
if(!flag) {
if(T[v].x == n && T[v].y == m) {
if(dx <= 1 || dy <= 1) {
if(dis[v] > dis[u] + 1 && !vis[v]) {
dis[v] = dis[u] + 1;
q.push(qnode(v , dis[v]));
}
}
}
else {
if(dis[v] > dis[u] + 1 && !vis[v]) {
dis[v] = dis[u] + 1;
q.push(qnode(v , dis[v]));
}
}
}
else {
if(dis[v] > dis[u] + 1 && !vis[v]) {
dis[v] = dis[u] + 1;
q.push(qnode(v , dis[v]));
}
}
}
}
}
}
}
int main() {
flag = 0;
scanf("%d%d%d" , &n , &m , &k);
for(int i = 1 ; i <= k ; i++) {
scanf("%d%d" , &T[i].x , &T[i].y);
if(T[i].x == n && T[i].y == m) flag = 1;
dis[i] = inf;
}
if(!flag) {
T[k + 1].x = n , T[k + 1].y = m;
k++;
dis[k] = inf;
}
dij();
if(dis[k] >= inf) printf("%d\n" , -1);
else printf("%lld\n" , dis[k]);
return 0;
}