http://uoj.ac/problem/107

设\(f(l,r,i,j)\)表示\([l,r]\)中的机器人聚集到\((i,j)\)需要花的最小操作数。

\(f(l,r,i,j)=\min\left\{\begin{array}{rcl}
f(l,k,i,j)+f(k+1,r,i,j)\\
f(l,r,i',j'),(i',j')\rightarrow(i,j)\end{array}\right.\)

斯坦纳树的模型,对于每个\([l,r]\)的状态,处理完第一行后再跑一遍双队列广搜处理第二行。

用基数排序优化,时间复杂度\(O(n^3+n^2hw)\)。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std; const int N = 503;
const int dx[4] = {-1, 0, 1, 0};
const int dy[4] = {0, -1, 0, 1}; struct data {
int x, y;
data (int _x = 0, int _y = 0) : x(_x), y(_y) {}
} to[N][N][4]; bool vis[N][N][4];
char s[N][N];
int f[10][10][N][N], n, w, h; data work(int x, int y, int tmp) {
if (vis[x][y][tmp]) return to[x][y][tmp];
vis[x][y][tmp] = true;
if (s[x][y] == 'A') (++tmp) &= 3;
if (s[x][y] == 'C') (--tmp) &= 3;
if (s[x + dx[tmp]][y + dy[tmp]] == 'x')
return data(x, y);
else
return to[x + dx[tmp]][y + dy[tmp]][tmp] = work(x + dx[tmp], y + dy[tmp], tmp);
} int tot = 0, l, r, id[N * N];
data q1[N * N], q2[N * N], tt; template <typename T> void check_min(T &a, T b) {if (b < a) a = b;}
template <typename T> void check_max(T &a, T b) {if (b > a) a = b;} bool cmp(data A, data B) {return f[l][r][A.x][A.y] < f[l][r][B.x][B.y];} int c[N * N * 20]; void BFS() {
// stable_sort(q1 + 1, q1 + tot + 1, cmp);
int mx = 0, num;
for (int i = 1; i <= tot; ++i) if ((num = f[l][r][q1[i].x][q1[i].y]) != 1010580540) check_max(mx, num);
memset(c, 0, sizeof(int) * (mx + 2));
for (int i = 1; i <= tot; ++i) {
num = f[l][r][q1[i].x][q1[i].y];
if (num != 1010580540) ++c[num];
else ++c[mx + 1];
}
for (int i = 1; i <= mx + 1; ++i) c[i] += c[i - 1];
for (int i = tot; i >= 1; --i) {
num = f[l][r][q1[i].x][q1[i].y];
if (num == 1010580540) num = mx + 1;
id[c[num]--] = i;
}
int head = 1, tail = 0, tmp = 1, x, y, x2, y2;
while (head <= tail || tmp <= tot) {
x = q2[head].x; y = q2[head].y;
x2 = q1[id[tmp]].x; y2 = q1[id[tmp]].y;
if (head <= tail && tmp <= tot && f[l][r][x][y] < f[l][r][x2][y2] || tmp > tot) ++head;
else ++tmp, x = x2, y = y2;
for (int d = 0; d < 4; ++d) {
tt = to[x][y][d];
if (tt.x == 0) continue;
if (f[l][r][tt.x][tt.y] > f[l][r][x][y] + 1) {
f[l][r][tt.x][tt.y] = f[l][r][x][y] + 1;
q2[++tail] = tt;
}
}
}
} int main() {
scanf("%d%d%d", &n, &w, &h); memset(f, 60, sizeof(f)); for (int i = 1; i <= h; ++i)
scanf("%s", s[i] + 1);
for (int i = 1; i <= h; ++i) s[i][0] = s[i][w + 1] = 'x';
for (int i = 1; i <= w; ++i) s[0][i] = s[h + 1][i] = 'x';
for (int i = 1 ; i <= h; ++i)
for (int j = 1; j <= w; ++j)
if (s[i][j] != 'x')
for (int dt = 0; dt < 4; ++dt)
to[i][j][dt] = work(i, j, dt); for (int i = 1; i <= h; ++i)
for (int j = 1; j <= w; ++j) q1[++tot] = data(i, j); bool flag;
for (int i = n; i >= 1; --i) {
flag = false;
for (int ii = 1; ii <= h; ++ii) {
for (int jj = 1; jj <= w; ++jj)
if (s[ii][jj] == '0' + i) {
f[i][i][ii][jj] = 0;
flag = true;
break;
}
if (flag) break;
}
l = r = i; BFS();
for (int j = i + 1; j <= n; ++j) {
for (int k = i; k < j; ++k)
for (int ii = 1; ii <= h; ++ii)
for (int jj = 1; jj <= w; ++jj)
check_min(f[i][j][ii][jj], f[i][k][ii][jj] + f[k + 1][j][ii][jj]);
l = i; r = j; BFS();
}
} int ans = 0x7fffffff;
for (int i = 1; i <= h; ++i)
for (int j = 1; j <= w; ++j)
check_min(ans, f[1][n][i][j]);
printf("%d\n", ans == 1010580540 ? -1 : ans);
return 0;
}

【UOJ #107】【APIO 2013】ROBOTS的更多相关文章

  1. 【UOJ #108】【APIO 2013】TOLL

    http://uoj.ac/problem/108 好神的一道题啊. 原图边权互不相同是重点! 如果有一个点集,有两组边集,要求这两组边集的并集的最小生成树,可以对两组边集分别求一下最小生成树构成新的 ...

  2. 【UOJ】67 新年的毒瘤 &【BZOJ】1123 BLO

    [UOJ 67] 题目链接: 传送门 题解: 第一眼很懵逼……这什么鬼. 思考什么点复合条件……(o(>﹏<)o 1.树,也就是说还剩n-2条边,等价于要删去一个度数为m-n+2的点. 2 ...

  3. 【UOJ#236】[IOI2016]railroad(欧拉回路,最小生成树)

    [UOJ#236][IOI2016]railroad(欧拉回路,最小生成树) 题面 UOJ 题解 把速度看成点,给定的路段看成边,那么现在就有了若干边,然后现在要补上若干边,以及一条\([inf,\) ...

  4. 【UOJ#177】欧拉回路

    [UOJ#177]欧拉回路 题面 UOJ 题解 首先图不连通就没啥好搞的了. 对于无向图而言,每个点度数为偶数. 对于有向图而言,每个点入度等于出度. 然后就是一本通上有的做法,直接\(dfs\)一遍 ...

  5. 【UOJ#311】【UNR #2】积劳成疾(动态规划)

    [UOJ#311][UNR #2]积劳成疾(动态规划) UOJ Solution 考虑最大值分治解决问题.每次枚举最大值所在的位置,强制不能跨过最大值,左右此时不会影响,可以分开考虑. 那么设\(f[ ...

  6. 【UOJ#450】【集训队作业2018】复读机(生成函数,单位根反演)

    [UOJ#450][集训队作业2018]复读机(生成函数,单位根反演) 题面 UOJ 题解 似乎是\(\mbox{Anson}\)爷的题. \(d=1\)的时候,随便怎么都行,答案就是\(k^n\). ...

  7. 【UOJ#246】套路(动态规划)

    [UOJ#246]套路(动态规划) 题面 UOJ 题解 假如答案的选择的区间长度很小,我们可以做一个暴力\(dp\)计算\(s(l,r)\),即\(s(l,r)=min(s(l+1,r),s(l,r- ...

  8. 【UOJ#340】【清华集训2017】小 Y 和恐怖的奴隶主(矩阵快速幂,动态规划)

    [UOJ#340][清华集训2017]小 Y 和恐怖的奴隶主(矩阵快速幂,动态规划) 题面 UOJ 洛谷 题解 考虑如何暴力\(dp\). 设\(f[i][a][b][c]\)表示当前到了第\(i\) ...

  9. 【UOJ#422】【集训队作业2018】小Z的礼物(min-max容斥,轮廓线dp)

    [UOJ#422][集训队作业2018]小Z的礼物(min-max容斥,轮廓线dp) 题面 UOJ 题解 毒瘤xzy,怎么能搬这种题当做WC模拟题QwQ 一开始开错题了,根本就不会做. 后来发现是每次 ...

随机推荐

  1. 网站开发中很有用的几个 jQuery 地图插件

    下面提到的 jQuery 地图插件不仅仅是提供一个简便的方式来安装一个地图,如果你想在它们之间选择一个放到你的网站上,那么它们还有更多的额外选项来提供更多更全面的功能.大部分的 jQuery 地图插件 ...

  2. jquery键盘事件全记录

    很多时候,我们需要获取用户的键盘事件,下面就一起来看看jquery是如何操作键盘事件的. 一.首先需要知道的是: 1.keydown() keydown事件会在键盘按下时触发. 2.keyup() k ...

  3. Netty 入门初体验

    Netty简介 Netty是一款异步的事件驱动的网络应用程序框架,支持快速开发可维护的高性能的面向协议的服务器和客户端.Netty主要是对java 的 nio包进行的封装 为什么要使用 Netty 上 ...

  4. ubuntu之安装pycharm编辑器

    pycharm是Java写的,运行需要Java环境. 安装java jdk sudo add-apt-repository ppa:webupd8team/java sudo apt-get upda ...

  5. ubuntu sougou输入法

    1, 打开搜狗输入法Linux版的官网http://pinyin.sogou.com/linux/?r=pinyin,并下载你需要的版本,这里选择64位版. 2,在Ubuntu14.01下可以直接点击 ...

  6. React 16 源码瞎几把解读 【前戏】 为啥组件外面非得包个标签?

    〇.看前准备 1.自行clone react最新代码 2.自行搭建一个能跑react的test项目 一.看表面:那些插件 如何解析JSX 有如下一段代码: // ---- hearder.jsx 组件 ...

  7. Linux阵列 RAID详解 (转)

    原文链接:http://molinux.blog.51cto.com/2536040/516008   一. RAID详解   二. mdadm工具介绍   三. 创建一个RAID的基本过程   四. ...

  8. Linux打补丁的一些问题

    linuxpatchlinux内核文档commandheader类unix操作系统有一个很有趣的特性就是源代码级的补丁包.在windows上我们打补丁都是运行一个可执行的程序,然后就可以把补丁打完了, ...

  9. P1084 疫情控制

    Solution 二分答案, 尽量往上跳, 不能跳到根节点. 仍然能跳的拿出来.看剩下的点没有覆盖哪个? 贪心的分配一下. Code 70 #include<iostream> #incl ...

  10. mysql一个字符问题

    顺便记录一下在使用mysql过程中碰到的一些问题: 有时候使用脚本迁移数据时会碰到乱码的问题,即使将表字符集设置成utf8也无济于事,这个时候在执行sql之前加一句set names utf8即可.