3205: [Apio2013]机器人

Time Limit: 15 Sec  Memory Limit: 128 MB
Submit: 953  Solved: 227
[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

4 10 5
1.........
AA...x4...
..A..x....
2....x....
..C.3.A...

Sample Output

5

HINT

第一步:向右推动 3 号机器人,当它碰到转向器后会向上继续移动,直至碰到墙壁停止移动。第二步:向上推动 4 号机器人,当它碰到墙壁后停止移动,与3 号机器人合并,构成  3-4 号机器人 第三步:向上推动 2 号机器人,当它碰到转向器后会向左移动,由于左侧为墙壁,故停留在原地。第四步:向右推动  2 号机器人,由于它在一个转向器上,故它会向上移动,直至碰到墙壁停止移动,与  1 号机器人合并,构成 1-2 号机器人。第五步:向左推动  3-4 号机器人,当它碰到墙壁后停止移动,与 1-2 号机器人合并,构成  1-4 号机器人。

≤ 9,≤ 500 且   h ≤ 500

分析:非常坑的一道题.

   这道题是斯坦纳树模型一眼就能看出来,令dp[l][r][x][y]表示编号为l~r的机器人所在(x,y)这个位置时的最少推动次数。 有dp[l][r][x][y]=min{dp[l][k][x][y]+dp[k+1][r][x][y]}或者dp[l][r][x][y]由其它dp[l][r][x1][y1]而来。 后者可以通过SPFA来解决。可以先预处理出每个位置朝4个方向推动最终会走到哪,用记忆花搜索处理.

   然后就到了最麻烦的地方了,普通的spfa算法会超时.注意到这道题的边权都是1,可以想到用bfs,但是这道题必须要用spfa转移,于是有了一个奇怪的优化:开两个队列q1,q2,一开始将所有点的距离排序后从小到大插入到q2中,每次取q1,q2队首较小的元素扩展,扩展得到的元素加入q1中.因为每次扩展元素大小只会+1嘛,所以q1和q2总是单调的.

   在spfa之前要对元素进行排序.这里的一个优化是计数排序.因为值域很小嘛,比sort要快.

   有上面几个优化还不够,每次清空vis数组会浪费大量的时间,因此还必须用时间戳优化.

   凭着四重优化:记忆化预处理,计数排序,“单调队列”的spfa,时间戳,终于能A掉此题了.get到不少新技能啊.

   犯了一个sb错误:记忆化搜索预处理的时候vis数组开成了两维的.因为方向也是一个影响量嘛,所以要开成三维的,以后要注意了.

#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <algorithm> using namespace std; const int inf = 0x7ffffff,dx[] = {-,,,},dy[] = {,-,,}; struct node
{
int x,y;
} pos[][][],q[ * ],tmp[ * ]; int num,n,m,f[][][][],vis[][][],dfs_clock,sx,sy,sizee,ans = inf,Time,rk[ * ];
int vis2[ * ],cnt[ * ],vis3[][],Time2;
char s[][]; void add(int x,int v,int c)
{
if (vis2[x] != c)
{
vis2[x] = c;
cnt[x] = ;
}
cnt[x] += v;
} int query(int x,int c)
{
if (vis2[x] != c)
{
vis2[x] = c;
cnt[x] = ;
}
return cnt[x];
} void sortt()
{
int maxx = ;
Time++;
for (int i = ; i <= sizee; i++)
{
node temp = q[i];
add(f[sx][sy][temp.x][temp.y],,Time);
maxx = max(maxx,f[sx][sy][temp.x][temp.y]);
}
for (int i = ; i <= maxx; i++)
add(i,query(i - ,Time),Time);
for (int i = ; i <= sizee; i++)
{
rk[i] = query(f[sx][sy][q[i].x][q[i].y],Time);
add(f[sx][sy][q[i].x][q[i].y],-,Time);
}
for (int i = ; i <= sizee; i++)
tmp[rk[i]] = q[i];
for (int i = ; i <= sizee; i++)
q[i] = tmp[i];
} bool check(int x,int y)
{
if (x <= || x > n || y <= || y > m)
return false;
if (s[x][y] == 'x')
return false;
return true;
} void spfa()
{
queue <node> q1,q2;
for (int i = ; i <= sizee; i++)
{
q2.push(q[i]);
vis3[q[i].x][q[i].y] = Time2;
}
while (!q1.empty() || !q2.empty())
{
node u;
if (q1.empty())
{
u = q2.front();
q2.pop();
}
else if (q2.empty())
{
u = q1.front();
q1.pop();
}
else
{ int t1 = f[sx][sy][q1.front().x][q1.front().y],t2 = f[sx][sy][q2.front().x][q2.front().y];
if (t1 < t2)
{
u = q1.front();
q1.pop();
}
else
{
u = q2.front();
q2.pop();
}
}
vis3[u.x][u.y] = ;
int x = u.x,y = u.y;
for (int i = ; i <= ; i++)
{
node temp = pos[x][y][i];
if (temp.x == - && temp.y == -)
continue;
int nx = temp.x,ny = temp.y;
if (check(nx,ny))
{
if (f[sx][sy][nx][ny] > f[sx][sy][x][y] + )
{
f[sx][sy][nx][ny] = f[sx][sy][x][y] + ;
if (vis3[nx][ny] != Time2)
{
vis3[nx][ny] = Time2;
node temp;
temp.x = nx;
temp.y = ny;
q1.push(temp);
}
}
}
}
}
} node dfs(int x,int y,int z)
{
if (vis[x][y][z] == dfs_clock)
{
node temp;
temp.x = temp.y = -;
return temp;
}
if (!(pos[x][y][z].x == && pos[x][y][z].y == ))
return pos[x][y][z];
vis[x][y][z] = dfs_clock;
int nowz = z;
if (s[x][y] == 'A')
nowz = (z + ) % ;
if (s[x][y] == 'C')
nowz = (z + ) % ;
int nx = x + dx[nowz],ny = y + dy[nowz];
if (!check(nx,ny))
{
node temp;
temp.x = x;
temp.y = y;
return temp;
}
return pos[x][y][z] = dfs(nx,ny,nowz);
} int main()
{
scanf("%d%d%d",&num,&m,&n);
for (int i = ; i <= num; i++)
for (int j = i; j <= num; j++)
for (int k = ; k <= n; k++)
for (int l = ; l <= m; l++)
f[i][j][k][l] = inf;
for (int i = ; i <= n; i++)
{
scanf("%s",s[i] + );
for (int j = ; j <= m; j++)
{
if (s[i][j] >= '' && s[i][j] <= '')
{
int id = s[i][j] - '';
f[id][id][i][j] = ;
}
}
}
for (int i = ; i <= n; i++)
for (int j = ; j <= m; j++)
for (int k = ; k <= ; k++)
{
node temp = pos[i][j][k];
if (!(temp.x == && temp.y == ))
continue;
if (s[i][j] == 'x')
continue;
++dfs_clock;
pos[i][j][k] = dfs(i,j,k);
}
for (int len = ; len <= num; len++)
{
for (int i = ; i + len - <= num; i++)
{
int j = i + len - ;
for (int p = i; p < j; p++)
{
for (int k = ; k <= n; k++)
{
for (int l = ; l <= m; l++)
{
f[i][j][k][l] = min(f[i][j][k][l],f[i][p][k][l] + f[p + ][j][k][l]);
}
}
}
sizee = ;
for (int k = ; k <= n; k++)
for (int l = ; l <= m; l++)
if (f[i][j][k][l] != inf)
{
node temp;
temp.x = k;
temp.y = l;
q[++sizee] = temp;
}
sx = i;
sy = j;
sortt();
Time2++;
spfa();
}
}
for (int i = ; i <= n; i++)
for (int j = ; j <= m; j++)
ans = min(ans,f[][num][i][j]);
if (ans == inf)
puts("-1");
else
printf("%d\n",ans); return ;
}

bzoj3205 [Apio2013]机器人的更多相关文章

  1. [Bzoj3205][Apio2013]机器人(斯坦纳树)(bfs)

    3205: [Apio2013]机器人 Time Limit: 15 Sec  Memory Limit: 128 MBSubmit: 977  Solved: 230[Submit][Status] ...

  2. bzoj千题计划230:bzoj3205: [Apio2013]机器人

    http://www.lydsy.com/JudgeOnline/problem.php?id=3205 历时一天,老子终于把它A了 哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈 因为不懂spfa ...

  3. [BZOJ3205][APIO2013]Robot(斯坦纳树)

    3205: [Apio2013]机器人 Time Limit: 15 Sec  Memory Limit: 128 MBSubmit: 1007  Solved: 240[Submit][Status ...

  4. BZOJ3205/UOJ107 [Apio2013]机器人

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  5. [APIO2013]机器人(斯坦纳树)

    题目描述 VRI(Voltron 机器人学会)的工程师建造了 n 个机器人.任意两个兼容的机 器人站在同一个格子时可以合并为一个复合机器人. 我们把机器人用 1 至 n 编号(n ≤ 9).如果两个机 ...

  6. [APIO2013]机器人[搜索、斯坦纳树]

    题意 题目链接 分析 记 g(d,x,y) 表示从 (x,y) 出发,方向为 d 到达的点,这个可以通过记忆化搜索求出,注意如果转移成环(此时向这个方向走没有意义)要特判. 记 f(l,r,x,y) ...

  7. 【题解】APIO2013机器人

    其实这题前前后后的思考时间加起来应该有两天之久了,dp状态,转移方式等等都还是比较好想,然而左看右看觉得spfa复杂度未免太爆炸……然后选择看了一篇题解,发现在多重优化之下,其实是可以过的…… 首先建 ...

  8. [APIO2013]机器人

    题目描述 VRI(Voltron 机器人学会)的工程师建造了 n 个机器人.任意两个兼容的机 器人站在同一个格子时可以合并为一个复合机器人. 我们把机器人用 1 至 n 编号(n ≤ 9).如果两个机 ...

  9. bzoj 3205: [Apio2013]机器人【dfs+斯坦纳树+spfa】

    第一次听说斯坦纳树这种东西 先dfs预处理出来dis[i][j][k]表示格子(i,j)向k方向转移能到哪,记忆话搜索预处理,注意如果有环的话特判一下 设f[i][j][x][y]表示复合机器人i-j ...

随机推荐

  1. Teaching Machines to Understand Us 让机器理解我们 之三 自然语言学习及深度学习的信仰

    Language learning 自然语言学习 Facebook’s New York office is a three-minute stroll up Broadway from LeCun’ ...

  2. 面向对象编程(OOP)思想小结

    Concepts 类(class):对我们要解决问题的抽象,比如建造房子的蓝图:但实现机制上来讲,类是根据蓝图构建而成的,存储在内存中的,用来表示对象的数据. 对象(object):根据类构建的实体, ...

  3. 3.openldap生成LDAP用户

    1.用migrationtools生成用户 #yum install migrationtools -y #vim /usr/share/migrationtools/migrate_common.p ...

  4. SVN服务器搭建及客户端配置

    为什么要使用SVN? 在程序的编写过程中,每个程序员都会负责开发一个或多个模块,且开发中会生成很多不同的版本, 这就需要程序员有效的管理代码,在需要的时候可以迅速,准确取出相应的版本. Subvers ...

  5. “我爱淘”第二冲刺阶段Scrum站立会议5

    完成任务: 完成了登录界面的实现,可以按照数据库中的用户名密码进行登录,. 计划任务: 在客户端实现分类功能,通过学院的分类查看书籍. 遇到问题: 再登录上了之后,并且保存密码,但是点击退出当前账号这 ...

  6. DataTable转List<T>集合

    #region DataTable转List集合 +static IList<T> DataTableToList<T>(DataTable dt) where T : cla ...

  7. lintcode-413-反转整数

    413-反转整数 将一个整数中的数字进行颠倒,当颠倒后的整数溢出时,返回 0 (标记为 32 位整数). 样例 给定 x = 123,返回 321 给定 x = -123,返回 -321 标签 整数 ...

  8. 【leetcode】215. Kth Largest Element in an Array

    Find the kth largest element in an unsorted array. Note that it is the kth largest element in the so ...

  9. window redis php(必须版本>=5.4) 安装

    1.下载redis的win版客户端 下载地址: http://code.google.com/p/servicestack/wiki/RedisWindowsDownload 2.选择32bit,64 ...

  10. dat.gui 上手

    dat.gui是款神器产品.一个调试利器.但是用起来很简单很简单 1:引用dat.gui.js. 2:实例化   this.gui = new dat.GUI(); 3:创建可设置一个数据对象.例如v ...