做法一:SPFA 。
建图是关键。终于把此坑补上, 貌似判能否踏过传送阵而不传送并没有什么卵用,判的话就麻烦了。
#include <cstdio>
#include <iostream>
#include <queue>
#include <cstring>
#define MAX_V (5000 + 50)
#define MAX_E (MAX_V << 4)
using namespace std;
const int dx[] = {0,1,0,-1,0};
const int dy[] = {0,0,1,0,-1};
int V = 0, E = 0, tot = 0, C;
char maps[MAX_V][MAX_V];
int first[MAX_V], nxt[MAX_E << 1], dis[MAX_V], door[MAX_V];
int vis[MAX_V][MAX_V];
bool used[MAX_V];
struct edge{
int from, to, cost;
}es[MAX_E << 1];
void build(int ff, int tt, int dd)
{
// cout << ff << " " << tt << " " << dd << endl;
es[++tot] = (edge){ff,tt,dd};
nxt[tot] = first[ff];
first[ff] = tot;
}
queue <int> q;
void spfa(int s)
{
memset(dis,63,sizeof(dis));
dis[s] = 0;
q.push(s);
used[s] = 1;
while(q.size())
{
int x = q.front();
q.pop();
used[x] = 0;
for(int i = first[x]; i != -1; i = nxt[i])
{
int v = es[i].to;
if(dis[v] > dis[x] + es[i].cost)
{
dis[v] = dis[x] + es[i].cost;
if(!used[v])
{
q.push(v);
used[v] = 1;
}
}
}
}
}
int main()
{
int n, m, cnt = 0;
cin >> n >> m >> C;
for(int i = 1; i <= n; i ++)
scanf("%s", maps[i]+1);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
vis[i][j] = ++V;
int Ts, Te;
memset(first,-1,sizeof(first));
for(int i = 1; i <= n; i ++)
{
for(int j = 1; j <= m; j ++)
{
if(maps[i][j] == 'P')
door[++cnt] = vis[i][j];
if(maps[i][j] == '#')
continue;
if(maps[i][j] == 'Y')
Ts = vis[i][j];
if(maps[i][j] == 'C')
Te = vis[i][j];
for(int k = 1; k <= 4; k ++)
{
int nx = i + dx[k];
int ny = j + dy[k];
if(nx >= 1 && nx <= n && ny >= 1 && ny <= m)
{
if(maps[nx][ny] == '#')
continue;
if(maps[nx][ny] == '*')
build(vis[i][j], vis[nx][ny], C);
else build(vis[i][j], vis[nx][ny], 0);
}
}
}
}
for(int i = 2; i <= cnt; i ++)
{
build(door[1], door[i], 0);
build(door[i], door[1], 0);
}
spfa(Ts);
if(dis[Te] >= 0x3f3f3f3f)
puts("screw you!");
else printf("%d\n", dis[Te]);
return 0;
}
做法二:bfs。
据说比spfa快。不是很难调。思路:读图时存起所有的传送阵的坐标,用bfs求最短路,每个坐标结构体有3个参数,分别是x,y,dis,dis表示当前点距离起点的最短距离,从起点开始扩展节点,若果遇到‘*’那么下一层时dis+=cost(代码里cost == t),bool 一个变量 表示是否是第一次遇到传送阵(如果有多个传送阵,那么我只需要第一个进入,如果第二次进入传送阵,一定不会比第一次进入优),然后使用读入时存起来的所有传送阵的信息,把除了第一次遇到的传送阵的传送阵们都加入队列作为待扩展节点,顺便将这些传送阵变成‘#’,不会再走这里,理由在前面括号里。
以上就是整个bfs 思路,但这个会超时,于是加一个dc教的强劲剪枝:如果当前的点的dis已经比我们之前搜过的ans大了,那么这条路肯定不是更优解,return;这个剪枝十分强♂劲;
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int MAXN = 5000 + 50;
int n, m, t;
int sx, sy, ex, ey, tot = 0;
char maps[MAXN][MAXN];
bool vis[MAXN][MAXN];
int ans = 2017483000;
int dx[] = {0,1,0,-1,0};
int dy[] = {0,0,1,0,-1};
bool had_in = 0;
struct Point{
int x, y, dis;
}P[MAXN << 1];
queue <Point> q;
void bfs(int x, int y)
{
int cnt = 0;
q.push((Point){x,y,0});
vis[x][y] = 1;
while(q.size())
{
Point p = q.front();
q.pop();
if(p.dis > ans)
return;
if(p.x == ex && p.y == ey)
ans = min(ans,p.dis);
for(int i = 1; i <= 4; i ++)
{
int nx = p.x + dx[i];
int ny = p.y + dy[i];
int nd = p.dis;
if(nx >= 1 && nx <= n && ny >= 1 && ny <= m && maps[nx][ny] != '#')
{
if(maps[nx][ny] == '*')
{
maps[nx][ny] = '#';
q.push((Point){nx,ny,p.dis+t});
}
else if(maps[nx][ny] == 'P' && !had_in)
{
had_in = 1;
for(int i = 1; i <= tot; i ++)
{
if(P[i].x != nx || P[i].y != ny)
{
maps[P[i].x][P[i].y] = '#';
q.push((Point){P[i].x,P[i].y,p.dis});
}
}
}
else q.push((Point){nx,ny,p.dis});
}
}
}
}
int main()
{
cin >> n >> m >> t;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
{
cin >> maps[i][j];
if(maps[i][j] == 'Y')
sx = i, sy = j;
else if(maps[i][j] == 'C')
ex = i, ey = j;
else if(maps[i][j] == 'P')
P[++tot] = ((Point){i,j,0});
}
bfs(sx,sy);
if(ans == 2017483000)
cout << "screw you!" << endl;
else cout << ans << endl;
return 0;
}
以上:2016-07-29 22:00
2016-9-28 20:15:01 重打:
2~3 ms codevs
#include <iostream>
#include <cstdio>
#include <queue>
#include <cstring>
using namespace std;
const int MAXN = 5000 + 50;
const int MAXP = 500 + 5;
const int dx[] = {0,0,-1,0,1};
const int dy[] = {0,1,0,-1,0};
int n, m, cost, sx, sy, ex, ey, tot = 0, ans = 1e9;
char maps[MAXN][MAXN];
bool vis[MAXN][MAXN];
struct Point{
int x, y, c;
}P[MAXP];
queue <Point> q;
void bfs(int sx, int sy)
{
vis[sx][sy] = 1;
q.push((Point){sx,sy,0});
while(q.size())
{
Point now = q.front();
q.pop();
for(int i = 1; i <= 4; i ++)
{
int nx = now.x + dx[i];
int ny = now.y + dy[i];
int nc = now.c;
if(nx >= 1 && nx <= n && ny >= 1 && ny <= m && maps[nx][ny] != '#' && !vis[nx][ny])
{
vis[nx][ny] = 1;
if(maps[nx][ny] == 'C')
ans = min(ans, nc);
else if(maps[nx][ny] == 'P')
{
maps[nx][ny] = '#';
for(int i = 1; i <= tot; i ++)
{
if(P[i].x == nx && P[i].y == ny)
continue;
maps[nx][ny] = '#';
q.push((Point){P[i].x,P[i].y,nc});
}
}
else if(maps[nx][ny] == '*')
if(nc+cost <= ans)
q.push((Point){nx,ny,nc+cost});
}
}
}
}
int main()
{
cin >> n >> m >> cost;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
{
char c = getchar();
while(c != 'Y' && c != 'C' && c != '#' && c != '*' && c != 'P')
c = getchar();
maps[i][j] = c;
if(c == 'Y')
sx = i, sy = j;
else if(c == 'C')
ex = i, ey = j;
else if(c == 'P')
P[++tot] = (Point){i,j,0};
}
bfs(sx,sy);
if(ans != 1e9)
cout << ans << endl;
else puts("screw you!");
return 0;
}
以上 2016-07-29 22:00
改了一下 小伙伴 的程序, 结果0 ms 过了, Orz。
我认为主要是他的程序中, 第一次找到 终点C 的时候就不在继续往下搜索了, 我自己找了一会也没找出反例, 这应该的确是最优的。Orz
以下是程序(我改):
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<queue>
using namespace std;
const int maxn=1005;
int dx[]={0,1,0,-1,0};
int dy[]={0,0,1,0,-1};
int n,m,v,k=0,cnt=0;
char map[maxn][maxn];
bool used[maxn][maxn];
int sx,sy,ex,ey;
struct dqs1
{
int x,y,cost;
};
queue <dqs1>q;
struct dqs2
{
int x,y;
}sb[maxn];
void move(dqs1 now)
{
dqs1 tui;
for(int i=1;i<=k;i++)
{
if(sb[i].x != now.x || sb[i].y != now.y)
{
tui.x=sb[i].x;
tui.y=sb[i].y;
tui.cost = now.cost;
q.push(tui);
map[tui.x][tui.y]='#';
}
}
}
bool check(int x,int y)
{
if(x>=1&&x<=n&&y>=1&&y<=m&&used[x][y]==0&&map[x][y]!='#')
return true;
return false;
}
void bfs()
{
dqs1 begin;
begin.x=sx;
begin.y=sy;
begin.cost=0;
used[sx][sy]=1;
q.push(begin);
while(!q.empty())
{
dqs1 head=q.front();
q.pop();
for(int i=1;i<=4;i++)
{
dqs1 now;
now.x=head.x+dx[i];
now.y=head.y+dy[i];
now.cost = head.cost;
if(check(now.x, now.y))
{
used[now.x][now.y]=1;
if(map[now.x][now.y]=='*')
{
now.cost=head.cost+v;
q.push(now);
}
else if(map[now.x][now.y]=='P')
move(now);//
else if(map[now.x][now.y]=='C')
{
printf("%d\n", now.cost);
return;
}
}
}
}
printf("screw you!\n");
return;
}
int main()
{
scanf("%d%d%d",&n,&m,&v);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
cin>>map[i][j];
if(map[i][j]=='Y')
{
sx=i;
sy=j;
}
if(map[i][j]=='P')
{
k ++;
sb[k].x=i;
sb[k].y=j;
}
}
bfs();
return 0;
}