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 号机器人。

≤ 9,≤ 500 且   h ≤ 500

分析:


斯坦纳树模型明显,预处理出每个点四个方向到达的点,这个bfs 即可,复杂度O(4 * n * m)
然后跑斯坦纳树,只转移二进制的1是连续的,最多跑45遍spfa。
 
然而还是超时,只有75分
发现边权恒为1,基数排序初始点,开两个数组,一个数组存排好序初始点,一个数组存spfa拓展点,两个数组恒有序,每次取两个数组中最小值作为当前点即可。
这样把spfa替换为bfs + 基数排序就有100了。(这道题dijkstra只有50 - 60,spfa却有75,是我脸太黑吗)

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 ;
}

[Bzoj3205][Apio2013]机器人(斯坦纳树)(bfs)的更多相关文章

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

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

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

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

  3. BZOJ 3205 [Apio2013]机器人 ——斯坦纳树

    腊鸡题目,实在卡不过去. (改了一下午) 就是裸的斯坦纳树的题目,一方面合并子集,另一方面SPFA迭代求解. 优化了许多地方,甚至基数排序都写了. 还是T到死,不打算改了,就这样吧 #include ...

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

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

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

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

  6. bzoj3205 [Apio2013]机器人

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

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

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

  8. 【BZOJ2595】游览计划(状压DP,斯坦纳树)

    题意:见题面(我发现自己真是越来越懒了) 有N*M的矩阵,每个格子有一个值a[i,j] 现要求将其中的K个点(称为关键点)用格子连接起来,取(i,j)的费用就是a[i,j] 求K点全部连通的最小花费以 ...

  9. HDU 4085 斯坦纳树

    题目大意: 给定无向图,让前k个点都能到达后k个点(保护地)中的一个,而且前k个点每个需要占据后k个中的一个,相互不冲突 找到实现这个条件达到的选择边的最小总权值 这里很容易看出,最后选到的边不保证整 ...

随机推荐

  1. glove 安装错误

    https://stackoverflow.com/questions/44921611/error-installing-glove-python-link-exe-failed-with-exit ...

  2. 转义字符 & sizeof & strlen

    在定义了数组大小时: sizeof是运算符,表示编译时分配的空间大小,即数组定义的大小,char t[20] = "sfa".sizeof: 20; strlen: 3.在未定义数 ...

  3. 同时使用多个UITableView

    1.xib\storyboard中给2个tableView设置constraints(等宽) 方法 : ①设置mainTableView的上\下\左\三部分的约束为0:subTableView上\下\ ...

  4. (8)zabbix监控项item是什么

    什么是item Items是从主机里面获取的所有数据.通常情况下我叫itme为监控项,例如服务器加入了zabbix监控,我需要监控它的cpu负载,那么实现这个方法的东西就叫item item构成 it ...

  5. centos6 安装windows字体

    注意:字体文件必须是TTF或者ttf格式的文件, 1.yum install -y fontconfig mkfontscale2.mkdir -p /usr/share/fonts/windows_ ...

  6. 【Gradle】Downloading https://services.gradle.org/distributions/gradle-3.3-bin.zip 失败

    提示连接超时 Downloading https://services.gradle.org/distributions/gradle-3.3-bin.zip 失败 这时候需要单独去官网下载包,然后放 ...

  7. NGINX宏观手记

    一.这里的优化主要是指对nginx的配置优化,一般来说nginx配置文件中对优化比较有作用的主要有以下几项: nginx进程数,建议按照cpu数目来指定,一般跟cpu核数相同或为它的倍数. ``` w ...

  8. 无法解析具体reference那个同名文件

    公司平台,如果src和gen文件系统中有同名文件.reference时会根据depend.cfg文件优先reference遇到的同名文件.这样如果存在同名文件且引用顺序不对就会有莫名的bug. 像rt ...

  9. python爬虫基础07-selenium大全1/8-安装和简单使用

    Selenium笔记(1)安装和简单使用 本文集链接:https://www.jianshu.com/nb/25338984 简介 Selenium是一个用于Web应用程序测试的工具. Seleniu ...

  10. SpringMVC之HandlerMapping源码分析

    01.doDispatch方法中代码如下:HandlerExecutionChain mappedHandler=this.getHandler(processedRequest) 02.Dispat ...