team2012-F3-sol-0013
从 Trac 迁移的文章
这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。
原文章内容如下:
{{{
题意:给定一个n*m的矩形场地,场地中有一些守卫,守卫按顺时针方向向四周巡视,每个时刻只看一个方向并有视野长度。
问从起点到终点最少被守卫看多少次,在此情况下最少时间是多少。
解法:将两个点之间的“距离”视为一个pair<被看到多少次,时间>,在这个4层的图上求起点到终点的最短路即可。
}}}
{{{
#include <iostream>
#include <cstdio>
#include <cstring>
#include <utility>
#include <queue>
using namespace std;
typedef pair<int, int> PII;
const int MAXN = 102;
const int INFI = 2100000000;
bool mp[MAXN][MAXN];
int n, m, s;
int st_x, st_y, end_x, end_y,
def[MAXN][MAXN][4];
PII dis[MAXN][MAXN][4];
bool inq[MAXN][MAXN][4];
struct ele
{
int x, y, t;
};
queue<ele> q;
int dir[4][2] = {
{0, 1}, {1, 0}, {0, -1}, {-1, 0}
};
bool check(int x, int y)
{
return (x && y && x<=n && y<=m);
}
int getdir(char ch)
{
if(ch == 'E') return 0;
if(ch == 'S') return 1;
if(ch == 'W') return 2;
if(ch == 'N') return 3;
}
int nextdir(int d)
{
return (d+1) % 4;
}
void gao()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=0;k<4;k++)
dis[i][j][k].first = dis[i][j][k].second = INFI;
dis[st_x][st_y][0].first = def[st_x][st_y][0];
dis[st_x][st_y][0].second = 0;
while(!q.empty()) q.pop();
memset(inq, 0, sizeof(inq));
ele start = {st_x, st_y, 0};
q.push(start);
while(!q.empty())
{
ele now = q.front();
q.pop();
inq[now.x][now.y][now.t] = 0;
for(int i=0;i<4;i++)
{
ele next = {now.x + dir[i][0], now.y + dir[i][1], (now.t+1) % 4};
if(!check(next.x, next.y))
continue;
if(mp[next.x][next.y] == 0)
{
PII a = make_pair(
dis[now.x][now.y][now.t].first+def[next.x][next.y][next.t],
dis[now.x][now.y][now.t].second+1);
if(a < dis[next.x][next.y][next.t])
{
dis[next.x][next.y][next.t] = a;
q.push(next);
inq[next.x][next.y][next.t] = 1;
}
}
}
}
}
int main()
{
while(~scanf("%d %d %d", &n, &m, &s))
{
memset(mp, 0, sizeof(mp));
for(int i=1;i<=n;i++)
{
getchar();
for(int j=1;j<=m;j++)
{
char ch;
scanf("%c", &ch);
if(ch == '*')
mp[i][j] = 1;
}
}
memset(def, 0, sizeof(def));
for(int i=1;i<=s;i++)
{
int x, y, l;
char d;
scanf("%d %d %d %c", &x, &y, &l, &d);
mp[x][y] = 1;
int dr = getdir(d);
for(int j=0;j<4;j++, dr = nextdir(dr))
{
int tx = x, ty = y;
for(int p=1;p<=l;p++)
{
tx += dir[dr][0];
ty += dir[dr][1];
if(!check(tx, ty))
break;
def[tx][ty][j]++;
}
}
}
scanf("%d %d %d %d", &st_x, &st_y, &end_x, &end_y);
gao();
PII ans = make_pair(INFI, INFI);
for(int i=0;i<4;i++)
if(dis[end_x][end_y][i] < ans)
ans = dis[end_x][end_y][i];
if(ans.first != INFI)
cout<<ans.first<<' '<<ans.second<<endl;
else
cout<<-1<<endl;
}
return 0;
}
}}}
题意:给定一个n*m的矩形场地,场地中有一些守卫,守卫按顺时针方向向四周巡视,每个时刻只看一个方向并有视野长度。
问从起点到终点最少被守卫看多少次,在此情况下最少时间是多少。
解法:将两个点之间的“距离”视为一个pair<被看到多少次,时间>,在这个4层的图上求起点到终点的最短路即可。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <utility>
#include <queue>
using namespace std;
typedef pair<int, int> PII;
const int MAXN = 102;
const int INFI = 2100000000;
bool mp[MAXN][MAXN];
int n, m, s;
int st_x, st_y, end_x, end_y,
def[MAXN][MAXN][4];
PII dis[MAXN][MAXN][4];
bool inq[MAXN][MAXN][4];
struct ele
{
int x, y, t;
};
queue<ele> q;
int dir[4][2] = {
{0, 1}, {1, 0}, {0, -1}, {-1, 0}
};
bool check(int x, int y)
{
return (x && y && x<=n && y<=m);
}
int getdir(char ch)
{
if(ch == 'E') return 0;
if(ch == 'S') return 1;
if(ch == 'W') return 2;
if(ch == 'N') return 3;
}
int nextdir(int d)
{
return (d+1) % 4;
}
void gao()
{
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int k=0;k<4;k++)
dis[i][j][k].first = dis[i][j][k].second = INFI;
dis[st_x][st_y][0].first = def[st_x][st_y][0];
dis[st_x][st_y][0].second = 0;
while(!q.empty()) q.pop();
memset(inq, 0, sizeof(inq));
ele start = {st_x, st_y, 0};
q.push(start);
while(!q.empty())
{
ele now = q.front();
q.pop();
inq[now.x][now.y][now.t] = 0;
for(int i=0;i<4;i++)
{
ele next = {now.x + dir[i][0], now.y + dir[i][1], (now.t+1) % 4};
if(!check(next.x, next.y))
continue;
if(mp[next.x][next.y] == 0)
{
PII a = make_pair(
dis[now.x][now.y][now.t].first+def[next.x][next.y][next.t],
dis[now.x][now.y][now.t].second+1);
if(a < dis[next.x][next.y][next.t])
{
dis[next.x][next.y][next.t] = a;
q.push(next);
inq[next.x][next.y][next.t] = 1;
}
}
}
}
}
int main()
{
while(~scanf("%d %d %d", &n, &m, &s))
{
memset(mp, 0, sizeof(mp));
for(int i=1;i<=n;i++)
{
getchar();
for(int j=1;j<=m;j++)
{
char ch;
scanf("%c", &ch);
if(ch == '*')
mp[i][j] = 1;
}
}
memset(def, 0, sizeof(def));
for(int i=1;i<=s;i++)
{
int x, y, l;
char d;
scanf("%d %d %d %c", &x, &y, &l, &d);
mp[x][y] = 1;
int dr = getdir(d);
for(int j=0;j<4;j++, dr = nextdir(dr))
{
int tx = x, ty = y;
for(int p=1;p<=l;p++)
{
tx += dir[dr][0];
ty += dir[dr][1];
if(!check(tx, ty))
break;
def[tx][ty][j]++;
}
}
}
scanf("%d %d %d %d", &st_x, &st_y, &end_x, &end_y);
gao();
PII ans = make_pair(INFI, INFI);
for(int i=0;i<4;i++)
if(dis[end_x][end_y][i] < ans)
ans = dis[end_x][end_y][i];
if(ans.first != INFI)
cout<<ans.first<<' '<<ans.second<<endl;
else
cout<<-1<<endl;
}
return 0;
}