2012-0013
从 Trac 迁移的文章
这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。
原文章内容如下:
还是让我这个苦逼的作者写吧T T
简单来说就是构图 + 最短路,直接贴代码:
复杂度O(|E|log|V|)
{{{
#include <cassert>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
const int maxN = 110;
const int len = (maxN * maxN) << 2;
const int inf = 0x7FFFFFFF;
const int dx[4] = {0, 1, 0, -1};
const int dy[4] = {1, 0, -1, 0};
typedef pair<int, int> Rec;
struct point
{
int v, w, next;
}edge[len << 2];
int n, m, s, g[4][maxN][maxN], vect[len], d[len], f[len]; //4层图, vect和edge大概就是一个前向星的东西
int r, tx, ty, st, ans_D, ans_F;
int tol, cnt, st_x, st_y, en_x, en_y;
bool vis[len];
char c;
int get(char c)
{
if (c == 'E') return 0;
if (c == 'S') return 1;
if (c == 'W') return 2;
if (c == 'N') return 3;
}
int mark(int t, int x, int y) //求时刻t坐标(x, y)的编号
{
return t * n * m + (x - 1) * m + y;
}
void add(int u, int v, int w) //添加边
{
//printf("%d %d %d \n", u, v, w);
cnt++;
edge[cnt].v = v;
edge[cnt].w = w;
edge[cnt].next = vect[u];
vect[u] = cnt;
}
void build() // 构图
{
st = mark(0, st_x, st_y);
tol = n * m * 4;
cnt = 0;
memset(vect, 0, sizeof(vect));
for (int t = 0; t < 4; t++){
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++){
if (g[t][i][j] == -1) continue;
for (int k = 0; k < 4; k++){
tx = i + dx[k];
ty = j + dy[k];
if (tx < 1 || ty < 1 || tx > n || ty > m) continue;
if (g[(t + 1) % 4][tx][ty] == -1) continue;
add(mark(t, i, j), mark((t + 1) % 4, tx, ty), g[(t + 1) % 4][tx][ty]);
}
}
}
}
}
void solve() //Dijkstra + priority_queue;数组d[u]表示到u的最少的守护者,f[u]表示最少的时间.
{
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= tol; i++){
d[i] = inf;
f[i] = inf;
}
d[st] = g[0][st_x][st_y];
f[st] = 0;
priority_queue< pair<int, Rec>, vector< pair<int, Rec> >, greater<pair<int, Rec> > > heap;
heap.push( make_pair(d[st], make_pair(f[st], st)));
while(!heap.empty()){
int u = heap.top().second.second;
heap.pop();
if (vis[u]) continue;
vis[u] = true;
for (int tt = vect[u]; tt; tt = edge[tt].next){
int v = edge[tt].v;
if (!vis[v]){
if (d[v] > d[u] + edge[tt].w || d[v] == d[u] + edge[tt].w && f[v] > f[u] + 1){
d[v] = d[u] + edge[tt].w;
f[v] = f[u] + 1;
heap.push( make_pair(d[v], make_pair(f[v], v) ) );
}
}
}
}
}
int main()
{
while(scanf("%d%d%d", &n, &m, &s) != EOF){
getchar();
assert(2 <= n && n <= 100);
assert(2 <= m && m <= 100);
assert(1 <= s && s <= n*m);
memset(g, 0, sizeof(g));
for (int i = 1; i <= n; i++){ //g记录地图的情况, -1表示不能走进,0表示空地,其他正数表示守护者看到这个格子的数目.
for (int j = 1; j <= m; j++){
c = getchar();
if (c == '*')
g[0][i][j] = g[1][i][j] = g[2][i][j] = g[3][i][j] = -1;
}
getchar();
}
int x, y;
for (int i = 1; i <= s; i++){
scanf("%d%d%d%c%c", &x, &y, &r, &c, &c);
assert(1 <= x && x <= n);
assert(1 <= y && y <= m);
assert(1 <= r && r <= 100);
assert(c == 'E' || c == 'S' || c == 'W' || c == 'N');
g[0][x][y] = g[1][x][y] = g[2][x][y] = g[3][x][y] = -1;
for (int k = 0; k < 4; k++){
for (int L = 1; L <= r; L++){
int t = (get(c) + k) % 4;
tx = x + dx[t] * L;
ty = y + dy[t] * L;
if (tx < 1 || ty < 1 || tx > n || ty > m) break;
if (g[k][tx][ty] != -1) g[k][tx][ty]++; //这里的k写成了t,悲剧.
}
}
}
scanf("%d%d%d%d", &st_x, &st_y, &en_x, &en_y);
build();
solve();
ans_D = ans_F = inf;
for (int t = 0; t < 4; t++){
int tp = mark(t, en_x, en_y);
if (ans_D > d[tp] || ans_D == d[tp] && ans_F > f[tp]){
ans_D = d[tp];
ans_F = f[tp];
}
}
if (ans_D == inf)
printf("-1\n");
else
printf("%d %d\n", ans_D, ans_F);
}
return 0;
}
}}}
=====================================
思考了一下之后觉得bfs貌似可以做><
还是让我这个苦逼的作者写吧T T
简单来说就是构图 + 最短路,直接贴代码:
复杂度O(|E|log|V|)
#include <cassert>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
const int maxN = 110;
const int len = (maxN * maxN) << 2;
const int inf = 0x7FFFFFFF;
const int dx[4] = {0, 1, 0, -1};
const int dy[4] = {1, 0, -1, 0};
typedef pair<int, int> Rec;
struct point
{
int v, w, next;
}edge[len << 2];
int n, m, s, g[4][maxN][maxN], vect[len], d[len], f[len]; //4层图, vect和edge大概就是一个前向星的东西
int r, tx, ty, st, ans_D, ans_F;
int tol, cnt, st_x, st_y, en_x, en_y;
bool vis[len];
char c;
int get(char c)
{
if (c == 'E') return 0;
if (c == 'S') return 1;
if (c == 'W') return 2;
if (c == 'N') return 3;
}
int mark(int t, int x, int y) //求时刻t坐标(x, y)的编号
{
return t * n * m + (x - 1) * m + y;
}
void add(int u, int v, int w) //添加边
{
//printf("%d %d %d \n", u, v, w);
cnt++;
edge[cnt].v = v;
edge[cnt].w = w;
edge[cnt].next = vect[u];
vect[u] = cnt;
}
void build() // 构图
{
st = mark(0, st_x, st_y);
tol = n * m * 4;
cnt = 0;
memset(vect, 0, sizeof(vect));
for (int t = 0; t < 4; t++){
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++){
if (g[t][i][j] == -1) continue;
for (int k = 0; k < 4; k++){
tx = i + dx[k];
ty = j + dy[k];
if (tx < 1 || ty < 1 || tx > n || ty > m) continue;
if (g[(t + 1) % 4][tx][ty] == -1) continue;
add(mark(t, i, j), mark((t + 1) % 4, tx, ty), g[(t + 1) % 4][tx][ty]);
}
}
}
}
}
void solve() //Dijkstra + priority_queue;数组d[u]表示到u的最少的守护者,f[u]表示最少的时间.
{
memset(vis, 0, sizeof(vis));
for (int i = 1; i <= tol; i++){
d[i] = inf;
f[i] = inf;
}
d[st] = g[0][st_x][st_y];
f[st] = 0;
priority_queue< pair<int, Rec>, vector< pair<int, Rec> >, greater<pair<int, Rec> > > heap;
heap.push( make_pair(d[st], make_pair(f[st], st)));
while(!heap.empty()){
int u = heap.top().second.second;
heap.pop();
if (vis[u]) continue;
vis[u] = true;
for (int tt = vect[u]; tt; tt = edge[tt].next){
int v = edge[tt].v;
if (!vis[v]){
if (d[v] > d[u] + edge[tt].w || d[v] == d[u] + edge[tt].w && f[v] > f[u] + 1){
d[v] = d[u] + edge[tt].w;
f[v] = f[u] + 1;
heap.push( make_pair(d[v], make_pair(f[v], v) ) );
}
}
}
}
}
int main()
{
while(scanf("%d%d%d", &n, &m, &s) != EOF){
getchar();
assert(2 <= n && n <= 100);
assert(2 <= m && m <= 100);
assert(1 <= s && s <= n*m);
memset(g, 0, sizeof(g));
for (int i = 1; i <= n; i++){ //g记录地图的情况, -1表示不能走进,0表示空地,其他正数表示守护者看到这个格子的数目.
for (int j = 1; j <= m; j++){
c = getchar();
if (c == '*')
g[0][i][j] = g[1][i][j] = g[2][i][j] = g[3][i][j] = -1;
}
getchar();
}
int x, y;
for (int i = 1; i <= s; i++){
scanf("%d%d%d%c%c", &x, &y, &r, &c, &c);
assert(1 <= x && x <= n);
assert(1 <= y && y <= m);
assert(1 <= r && r <= 100);
assert(c == 'E' || c == 'S' || c == 'W' || c == 'N');
g[0][x][y] = g[1][x][y] = g[2][x][y] = g[3][x][y] = -1;
for (int k = 0; k < 4; k++){
for (int L = 1; L <= r; L++){
int t = (get(c) + k) % 4;
tx = x + dx[t] * L;
ty = y + dy[t] * L;
if (tx < 1 || ty < 1 || tx > n || ty > m) break;
if (g[k][tx][ty] != -1) g[k][tx][ty]++; //这里的k写成了t,悲剧.
}
}
}
scanf("%d%d%d%d", &st_x, &st_y, &en_x, &en_y);
build();
solve();
ans_D = ans_F = inf;
for (int t = 0; t < 4; t++){
int tp = mark(t, en_x, en_y);
if (ans_D > d[tp] || ans_D == d[tp] && ans_F > f[tp]){
ans_D = d[tp];
ans_F = f[tp];
}
}
if (ans_D == inf)
printf("-1\n");
else
printf("%d %d\n", ans_D, ans_F);
}
return 0;
}
=====================================
思考了一下之后觉得bfs貌似可以做><