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

  首先建立状态,这个应该比较明显:\(f[l][r][x][y]\) 代表合并完区间 \(l\) ~\(r\) 之后,机器人停在 \(x,y\) 处所需要的最少移动次数。转移状态即为:

  \(f[l][r][x][y] = f[l][k][x][y] + f[k + 1][r][x][y] \left ( l <= k <= r \right )\)

\(f[l][r][x][y] = f[l][r][x'][y'] + 1 \)

  其中第二个转移发生的条件是 \(x',y'\) 可以一步到达 \(x,y\)。第二个转移状态就是在之前的博客中所提及的那样:1.满足三角形不等式;2.不满足拓扑序;针对这样的转移,我们用 spfa 来优化 dp 的转移。注意在这张图中,边权均为1。在单源的最短路中,这样的图spfa可以优化为bfs, 在多源最短路中我们可以使用两个队列来进行优化。这两个队列分别存储新增的节点 & 被松弛所以要去松弛其余节点的节点。这样将节点分类之后,每一次取出队首元素权值更小的进行松弛操作。我们会发现第二个队列中节点的权值是单调的(在边权为1的图中,先访问到的节点权值更小),而第一个队列中的元素我们使用基数排序来排。(并不知道为什么要用基数排序,或许就是比较快吧?)

  然后这份代码是我抄的大佬的代码,非常感谢了。其中有一个小小的技巧:memset的时候默认赋给节点当前数据类型的最大值,相加会溢出。但对于这种没有正负要求的,我们可以利用 unsigned 自然溢出使得结果依然是最大值。(・ω<)☆ 感觉这题还是挺毒的,差点就被毒死了……

#include <bits/stdc++.h>
using namespace std;
#define maxn 505
#define maxk 400000
#define uns unsigned short
#define INF 32639
int n, W, H, ans = INF;
int mark[maxn][maxn][];
int L, R;
uns f[][][maxn][maxn];
int cnt, top, tank[maxk], S[maxk];
char Map[maxn][maxn];
bool vis[maxn][maxn];
int dxy[][] = {{,}, {,}, {,-}, {-,}}; struct node
{
int x, y;
node(int xx = , int yy = ) { x = xx, y = yy; }
}g[maxn][maxn][], pos[], q[maxk];
queue <node> q1, q2; int read()
{
int x = , k = ;
char c;
c = getchar();
while(c < '' || c > '') { if(c == '-') k = -; c = getchar(); }
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * k;
} void gmin(uns &x, uns y) { x = x > y ? y : x; } node dfs(int x, int y, int k)
{
if(mark[x][y][k] == cnt) return g[x][y][k] = node (-, -);
mark[x][y][k] = cnt;
if(g[x][y][k].x != && g[x][y][k].y != ) return g[x][y][k];
int pre = k;
if(Map[x][y] == 'A') k = (k + ) % ;
else if(Map[x][y] == 'C') k = (k + ) % ;
int xx = x + dxy[k][], yy = y + dxy[k][];
if(xx < || yy < || xx > H || yy > W || Map[xx][yy] == 'x') return g[x][y][pre] = node(x, y);
return g[x][y][pre] = dfs(xx, yy, k);
} void spfa()
{
memset(tank, , sizeof(tank));
for(int i = ; i <= top; i ++) tank[f[L][R][q[i].x][q[i].y]] ++;
for(int i = ; i <= INF; i ++) tank[i] += tank[i - ];
for(int i = ; i <= top; i ++) S[tank[f[L][R][q[i].x][q[i].y]] --] = i;
for(int i = ; i <= top; i ++) q1.push(q[S[i]]);
top = ;
while(!q1.empty() || !q2.empty())
{
node now;
if(q1.empty()) now = q2.front(), q2.pop();
else if(q2.empty()) now = q1.front(), q1.pop();
else
{
int x1 = q1.front().x, y1 = q1.front().y;
int x2 = q2.front().x, y2 = q2.front().y;
if(f[L][R][x1][y1] <= f[L][R][x2][y2]) now = q1.front(), q1.pop();
else now = q2.front(), q2.pop();
}
vis[now.x][now.y] = ;
for(int i = ; i < ; i ++)
{
node v = g[now.x][now.y][i];
if(v.x == - || v.y == -) continue;
if(f[L][R][v.x][v.y] > f[L][R][now.x][now.y] + )
{
f[L][R][v.x][v.y] = f[L][R][now.x][now.y] + ;
if(!vis[v.x][v.y]) vis[v.x][v.y] = , q2.push(v);
}
}
}
} int main()
{
n = read(), W = read(), H = read();
memset(f, , sizeof(f));
for(int i = ; i <= H; i ++)
{
scanf("%s", Map[i] + );
for(int j = ; j <= W; j ++)
if(Map[i][j] > '' && Map[i][j] <= '')
pos[Map[i][j] - ''] = node(i, j);
}
for(int i = ; i <= H; i ++)
for(int j = ; j <= W; j ++)
if(Map[i][j] != 'x')
for(int k = ; k < ; k ++)
++ cnt, dfs(i, j, k);
for(int i = ; i <= n; i ++)
{
vis[pos[i].x][pos[i].y] = ;
q[++ top] = pos[i];
L = R = i; f[i][i][pos[i].x][pos[i].y] = ;
spfa();
}
for(int l = , j; l <= n; l ++)
for(int i = ; (j = i + l - ) <= n; i ++)
{
for(int x = ; x <= H; x ++)
for(int y = ; y <= W; y ++)
{
for(int k = i; k < j; k ++)
gmin(f[i][j][x][y], f[i][k][x][y] + f[k + ][j][x][y]);
if(f[i][j][x][y] < INF) q[++ top] = node(x, y), vis[x][y] = ;
}
L = i, R = j; spfa();
}
unsigned short ans = INF;
for(int i = ; i <= H; i ++)
for(int j = ; j <= W; j ++)
ans = min(ans, f[][n][i][j]);
if(ans < INF) printf("%u\n", ans);
else printf("-1\n");
return ;
}

【题解】APIO2013机器人的更多相关文章

  1. bzoj3205 [Apio2013]机器人

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

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

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

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

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

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

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

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

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

  6. BZOJ3205/UOJ107 [Apio2013]机器人

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

  7. [APIO2013]机器人

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

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

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

  9. 【BZOJ3205_洛谷3638】[APIO2013]机器人(动态规划)

    题目: 洛谷3638 分析: 卡了一天的神题--(OrzJumpmelon) 首先预处理出从点\(p\)向\(d\)方向出发最终能到达的点\(nxt[p][d]\).这个可以直接记忆化搜索解决.如果出 ...

随机推荐

  1. web pack

    WebPack是模块捆绑器,如果你的代码跨越了不同模块(例如不同Javascript文件),web pack可以将这些零散的代码构建到浏览器可读单个文件中. web pack还可以作为构建通道,你可以 ...

  2. vertical-align垂直居中

    <div id="content"> <div id="weizi"> 锄禾日当午,<br> 汗滴禾下土.<br> ...

  3. Docker与FastDFS的安装命令及使用

    Docker特点 1)上手快 用户只需要几分钟,就可以把自己的程序“Docker 化”.Docker 依赖于“写时复制” (copy-on-write)模型,使修改应用程序也非常迅速,可以说达到“随心 ...

  4. MySQL innodb表使用表空间物理文件复制或迁移表

    MySQL InnoDB引擎的表通过拷贝物理文件来进行单表或指定表的复制,可以想到多种方式,今天测试其中2种: 将innodb引擎的表修改为Myisam引擎,然后拷贝物理文件 直接拷贝innodb的表 ...

  5. Linux上面安装redis和简单使用

    一.安装,redis的官方的网址   https://redis.io/ 目前的最高的版本是4.0,我安装的是2.*的版本 1.下载源码,解压后编译源码. $ wget http://download ...

  6. MySQL的边角料

    //1查询对应数据库所有的表 SELECT * FROM information_schema.`TABLES` WHERE TABLE_SCHEMA ="数据库名" 2 查询数据 ...

  7. Hadoop(14)-MapReduce框架原理-切片机制

    1.FileInputFormat切片机制 切片机制 比如一个文件夹下有5个小文件,切片时会切5个片,而不是一个片 案例分析 2.FileInputFormat切片大小的参数配置 源码中计算切片大小的 ...

  8. C语言实例解析精粹学习笔记——31

    实例31: 判断字符串是否是回文 思路解析: 引入两个指针变量(head和tail),开始时,两指针分别指向字符串的首末字符,当两指针所指字符相等时,两指针分别向后和向前移动一个字符位置,并继续比较, ...

  9. JAVA 基础编程练习题

    1 [程序 1 不死神兔] 题目:古典问题:有一对兔子,从出生后第 3 个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问每个月的兔子对数为多少?程序分析: 兔子的规 ...

  10. STL 一些常用的STL函数(持续更新

    先说一下  一边要用到算法的东西一般要加#include<algorithm>头文件 一.栈和队列 1 栈 :一种线性表 特点  后进先出 头文件  #include<stack&g ...