[Bzoj3205][Apio2013]机器人(斯坦纳树)(bfs)
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 ;
- }
[Bzoj3205][Apio2013]机器人(斯坦纳树)(bfs)的更多相关文章
- [BZOJ3205][APIO2013]Robot(斯坦纳树)
3205: [Apio2013]机器人 Time Limit: 15 Sec Memory Limit: 128 MBSubmit: 1007 Solved: 240[Submit][Status ...
- [APIO2013]机器人(斯坦纳树)
题目描述 VRI(Voltron 机器人学会)的工程师建造了 n 个机器人.任意两个兼容的机 器人站在同一个格子时可以合并为一个复合机器人. 我们把机器人用 1 至 n 编号(n ≤ 9).如果两个机 ...
- BZOJ 3205 [Apio2013]机器人 ——斯坦纳树
腊鸡题目,实在卡不过去. (改了一下午) 就是裸的斯坦纳树的题目,一方面合并子集,另一方面SPFA迭代求解. 优化了许多地方,甚至基数排序都写了. 还是T到死,不打算改了,就这样吧 #include ...
- [APIO2013]机器人[搜索、斯坦纳树]
题意 题目链接 分析 记 g(d,x,y) 表示从 (x,y) 出发,方向为 d 到达的点,这个可以通过记忆化搜索求出,注意如果转移成环(此时向这个方向走没有意义)要特判. 记 f(l,r,x,y) ...
- bzoj 3205: [Apio2013]机器人【dfs+斯坦纳树+spfa】
第一次听说斯坦纳树这种东西 先dfs预处理出来dis[i][j][k]表示格子(i,j)向k方向转移能到哪,记忆话搜索预处理,注意如果有环的话特判一下 设f[i][j][x][y]表示复合机器人i-j ...
- bzoj3205 [Apio2013]机器人
3205: [Apio2013]机器人 Time Limit: 15 Sec Memory Limit: 128 MBSubmit: 953 Solved: 227[Submit][Status] ...
- bzoj千题计划230:bzoj3205: [Apio2013]机器人
http://www.lydsy.com/JudgeOnline/problem.php?id=3205 历时一天,老子终于把它A了 哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈 因为不懂spfa ...
- 【BZOJ2595】游览计划(状压DP,斯坦纳树)
题意:见题面(我发现自己真是越来越懒了) 有N*M的矩阵,每个格子有一个值a[i,j] 现要求将其中的K个点(称为关键点)用格子连接起来,取(i,j)的费用就是a[i,j] 求K点全部连通的最小花费以 ...
- HDU 4085 斯坦纳树
题目大意: 给定无向图,让前k个点都能到达后k个点(保护地)中的一个,而且前k个点每个需要占据后k个中的一个,相互不冲突 找到实现这个条件达到的选择边的最小总权值 这里很容易看出,最后选到的边不保证整 ...
随机推荐
- Bootstrap历练实例:导航内下拉菜单的用法
<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content=&q ...
- shell脚本,awk数组之如何处理多个文件。
[root@localhost | > file [root@localhost - | > file1 [root@localhost awk]# cat file [root@loca ...
- javaEE(15)_Servlet过滤器
一.Filter简介 1.Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,WEB开发人员通过Filter技术,对web服务器管理的所有web资源:例如Jsp, Servlet, ...
- js的命令模式
命令模式: 什么叫命令模式: 将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能. 命令模式主要有四个部分: 命令对象(comma ...
- 51nod 1242 斐波那契数列的第N项——数学、矩阵快速幂
普通算法肯定T了,所以怎么算呢?和矩阵有啥关系呢? 打数学符号太费时,就手写了: 所以求Fib(n)就是求矩阵 | 1 1 |n-1 第一行第一列的元素. | 1 0 | 其实学过线代 ...
- noip_最后一遍_2-图论部分
大体按照 数学 图论 dp 数据结构 这样的顺序 模板集 这个真的只有模板了……………… ·spfa #include<bits/stdc++.h> using namespace std ...
- luogu2312 解方程 (数论,hash)
luogu2312 解方程 (数论,hash) 第一次外出学习讲过的题目,然后被讲课人的一番话惊呆了. 这个题,我想着当年全国只有十几个满分.....然后他又说了句我考场A这道题时,用了5个模数 确实 ...
- (7)zabbix资产清单inventory管理
概述 监控的设备越来越多,有时候搞不清楚哪台服务器是什么配置,大多公司有自己的资产清单,要去专门的系统查询显得多少有点麻烦.为此,zabbix专门设置了设备资产管理功能. 我们创建或编辑主机的时候,可 ...
- C++实现简易单向链表
#include <iostream> #include <stdlib.h> #include <stdbool.h> using namespace std; ...
- verilog behavioral modeling ---Block statements
block statements : 1. sequential block : begin-end block 2.parallel block : fork - join bloc ...