3205: [Apio2013]机器人
Time Limit: 15 Sec Memory Limit: 128 MB
Submit: 977 Solved: 230
[Submit][Status][Discuss]
Description
VRI(Voltron机器人学会)的工程师建造了 n个机器人。任意两个兼容的机器人站在同一个格子时可以合并为一个复合机器人。我们把机器人用 1至 n编号(n ≤ 9)。如果两个机器人的编号是连续的,那么它们是兼容的,可以合并成一个复合机器人。最初这 n 个机器人各自都只有唯一的编号。而一个由两个或以上的机器人合并构成的复合机器人拥有两个编号,分别是构成它的所有机器人中最小和最大的编号。例如, 2号机器人只可以与 1号或 3号机器人合并。若 2号机器人与 3号机器人合并,可构成编号为 2-3的复合机器人。如果编号为 2-3的复合机器人与编号为 4-6的复合机器人合并,可构成编号为 2-6的复合机器人。当所有机器人合并以后则构成 1-n复合机器人。工程师把这 n个机器人放在了一个封闭的房间中,房间四周均是墙。该房间被划分成 w h 个方格。有些方格有障碍物,机器人不可经过或停留;其余方格允许多个机器人停留,同时允许机器人经过。任何时候一个机器人只占用一个方格。初始时刻,所有机器人均在不同的方格中。这些原始的机器人不会自发地移动。它们只有被工程师沿 x轴或 y轴推动后,才会沿推动的方向不断向前直线移动,直至碰到障碍物或墙停止移动。停止移动后,它会扫描当前的格子是否存在可以与它合并的机器人,如果有,则合并并继续检查,直至不能再合并为止。工程师只能沿水平向左、水平向右、竖直向上、竖直向下四个方向推动机器人,并且,在机器人尚未停止移动时,不允许推动其它机器人,因此任何时刻,房间中都只能有一个机器人移动,为了帮助机器人转向,工程师在一些格子中放置了转向器。具体地说,转向器分为顺时针转向器(右转器)和逆时针转向器(左转器),顺时针转向器可以使到达该格子的机器人沿顺时针方向转向 90_;逆时针转向器可以使到达该格子的机器人沿逆时针方向转向 90_。现在,我们将告诉你初始时刻房间内的信息。请你计算工程师最少共计需要推动机器人多少次,才能把所有的 n个机器人全部合并(如果可能的话)。
Input
你的程序必须从标准输入读入。输入的第 1行包含 3个整数 n、w和 h,用空格隔开。输入文件中接下来的 h行描述初始时刻房间内的信息,每行包含w个字符。这w* h 字符中每一个表示房间中的一个格子,意义如下:
‘ 1’至‘9’:表示该方格中有一个机器人,编号为这个数字;
‘ x’:表示该方格有障碍物;
‘ A’:表示该方格中有一个逆时针转向器;
‘ C’:表示该方格中有一个顺时针转向器;
‘ .’:表示该方格为空地。
Output
你的程序必须输出到标准输出。输出仅一个整数,表示最少需要推动的次数。
若不能使所有机器人全部合并,输出-1。
Sample Input
.........
AA...x4...
..A..x....
....x....
..C..A...
Sample Output
HINT
第一步:向右推动 3 号机器人,当它碰到转向器后会向上继续移动,直至碰到墙壁停止移动。第二步:向上推动 4 号机器人,当它碰到墙壁后停止移动,与3 号机器人合并,构成 3-4 号机器人 第三步:向上推动 2 号机器人,当它碰到转向器后会向左移动,由于左侧为墙壁,故停留在原地。第四步:向右推动 2 号机器人,由于它在一个转向器上,故它会向上移动,直至碰到墙壁停止移动,与 1 号机器人合并,构成 1-2 号机器人。第五步:向左推动 3-4 号机器人,当它碰到墙壁后停止移动,与 1-2 号机器人合并,构成 1-4 号机器人。
n ≤ 9,w ≤ 500 且 h ≤ 500
分析:
斯坦纳树模型明显,预处理出每个点四个方向到达的点,这个bfs 即可,复杂度O(4 * n * m)
AC代码:
# include <iostream>
# include <cstdio>
# include <queue>
# include <cstring>
using namespace std;
const int N = ;
const int M = << ;
char map[N][N];int to[][N * N],cnt,flag[M];bool vis[][N * N];
int d1[] = {,-,,},d2[] = {,,-,},ret = ;
int head[N * N],dt,K,n,m,a[],p;
int id(int x,int y){return (x - ) * m + y;}
struct node{
int dir,x,y;
node(){}
node(int dir,int x,int y):dir(dir),x(x),y(y){}
int w(){return to[dir][id(x,y)];}
void mark(int c){vis[dir][id(x,y)] = c;}
}que[N * N * ],tmp;
struct Edge{
int to,nex;
}edge[N * N * ];
void AddEdge(int u,int v)
{
if(u == v)return;
edge[++p] = (Edge){v,head[u]};
head[u] = p;
}
void Get(int &s,int x,int y,int dir)
{
que[cnt = ] = node(dir,x,y);que[cnt].mark();int cx,cy,D;
while(true)
{
tmp = que[cnt];D = tmp.dir;
if(que[cnt].w()){s = que[cnt].w();break;}
if(map[tmp.x][tmp.y] == 'C')
D = (D - + ) % ;
if(map[tmp.x][tmp.y] == 'A')
D = (D + ) % ;
cx = tmp.x + d1[D];cy = tmp.y + d2[D];
if(cx < || cx > n || cy < || cy > m || map[cx][cy] == 'x'){s = id(tmp.x,tmp.y);break;}
que[++cnt] = node(D,cx,cy);
if(vis[D][id(cx,cy)]){s = -;break;}
que[cnt].mark();
}
ret += cnt;
for(int i = ;i <= cnt;i++)
que[i].mark(),to[que[i].dir][id(que[i].x,que[i].y)] = s;
}
int bac[N * N * ],que1[N * N * ],que2[N * N * ],dist[][N * N],h1,h2;
void bfs(int sa)
{
h1 = h2 = ;int u;
while(h1 < que1[] || h2 < que2[])
{
if(h1 == que1[])u = que2[++h2];
else if(h2 == que2[])u = que1[++h1];
else if(dist[sa][que1[h1 + ]] <= dist[sa][que2[h2 + ]])u = que1[++h1];
else u = que2[++h2];
if(vis[][u])continue;
vis[][u] = true;
for(int i = head[u];i;i = edge[i].nex)if(dist[sa][u] + < dist[sa][edge[i].to])
{
dist[sa][edge[i].to] = dist[sa][u] + ;
que2[++que2[]] = edge[i].to;
}
}
for(int i = ;i <= h2;i++)vis[][que2[i]] = false;
for(int i = ;i <= h1;i++)vis[][que1[i]] = false;
}
int main()
{
freopen("ROBOTS.in","r",stdin);
freopen("ROBOTS.out","w",stdout);
scanf("%d %d %d",&K,&m,&n);
for(int i = ;i <= n;i++)scanf("%s",map[i] + );
for(int i = ;i <= n;i++)
for(int j = ;j <= m;j++)
{
if(map[i][j] >= '' && map[i][j] <= '')a[map[i][j] - '' - ] = id(i,j);
for(int k = ;k < ;k++)
{
Get(to[k][id(i,j)],i,j,k);
if(to[k][id(i,j)] != -)AddEdge(id(i,j),to[k][id(i,j)]);
}
}
memset(dist,0x3f3f3f3f,sizeof dist);
for(int i = ;i < K;i++)
{
int r = ;
for(int j = i;j < K;j++)r += ( << j),flag[r] = ++dt;
dist[flag[ << i]][a[i]] = ;
}
int all = << K;
for(int sa = ;sa < all;sa++)
{
if(!flag[sa])continue;
for(int s = sa & (sa - );s;s = sa & (s - ))
{
if(!flag[s] || !flag[sa ^ s])continue;
for(int i = ;i <= n * m;i++)
if(dist[flag[s]][i] + dist[flag[sa ^ s]][i] < dist[flag[sa]][i])
dist[flag[sa]][i] = dist[flag[s]][i] + dist[flag[sa ^ s]][i];
}
que1[] = que2[] = ;
for(int i = ;i <= n * m;i++)bac[i] = ;
for(int i = ;i <= n * m;i++)if(dist[flag[sa]][i] < dist[][])
bac[dist[flag[sa]][i]]++;
for(int i = ;i <= n * m;i++)bac[i] += bac[i - ];
que1[] = bac[n * m];
for(int i = ;i <= n * m;i++)if(dist[flag[sa]][i] < dist[][])
que1[bac[dist[flag[sa]][i]]--] = i;
bfs(flag[sa]);
}
int ret = dist[][];
for(int i = ;i <= n * m;i++)ret = min(ret,dist[flag[all - ]][i]);
printf("%d\n",ret == dist[][] ? - : ret);
fclose(stdin);
fclose(stdout);
return ;
}