【BZOJ】【3205】【APIO2013】机器人robot

斯坦纳树



  好神啊……Orz zyf && PoPoQQQ

  为啥跟斯坦纳树扯上关系了?我想是因为每个点(robot)都沿着树边汇到根的时候就全部合起来了吧= =这个好像和裸的斯坦纳树不太一样,那个是无向最小生成树,这个是有向图……

  引用题解:

令f[l][r][i][j]表示在点(i,j)将编号在[l,r]区间内的机器人全部合并的最小推动次数

则有动规方程组:

f[l][r][i][j]=min{f[l][r][_i][_j]+1} ( (_i,_j)->(i,j) )

f[l][r][i][j]=min(f[l][temp][i][j]+f[temp+1][r][i][j]) (l<=temp<r)

我们首先用记忆化搜索处理出每个点向四个方向推动后会到哪

然后利用根据这两个方程跑斯坦纳树即可

下面是细节部分:

1.转向器有环 因此会无限递归爆系统栈 标记一下就好

2.处理上面那个之后本机测还是会爆系统栈 没事交上去就不爆了

3.SPFA有一个优化 不加会T

观察这个图 发现所有边的边权都是1 如果是单源的话SPFA可以进化成广搜

现在是多源 因此我们可以这样做:

维护两个队列,将初始所有的点按照距离排序后从小到大加入队列1

每次拓展出的点加入队列2

每次取出点的时候,如果队列1队尾元素的距离小于队列2 就把队列1的队尾元素拿去松弛 否则就用队列2的

这样做之后除了排序之外复杂度是线性的

排序的log可以用计数排序省掉,但是直接sort也能过,无妨

然后这题就搞掉了。。。。。。

但是蒟蒻的快排程序就TLE了啊……然后用计数排序的MLE了QAQ

只能献上我的膝盖

  1 //APIO 2013 robots
  2 #include<queue>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<cstdlib>
  6 #include<iostream>
  7 #include<algorithm>
  8 #define rep(i,n) for(int i=0;i<n;++i)
  9 #define F(i,j,n) for(int i=j;i<=n;++i)
 10 #define D(i,j,n) for(int i=j;i>=n;--i)
 11 #define pb push_back
 12 using namespace std;
 13 typedef long long LL;
 14 inline int getint(){
 15     int r=1,v=0; char ch=getchar();
 16     for(;!isdigit(ch);ch=getchar()) if(ch==‘-‘)r=-1;
 17     for(; isdigit(ch);ch=getchar()) v=v*10+ch-‘0‘;
 18     return r*v;
 19 }
 20 const int N=510,INF=1e9;
 21 #define debug
 22 /*******************template********************/
 23 const int fx[]={1,0,-1,0},
 24             fy[]={0,1,0,-1};//down,right,up,left
 25 int n,w,h,mp[N][N],vis[N][N][4],ti;
 26 char s[N];
 27 struct pii{int X,Y;}G[N][N][4],b[N*N];
 28 queue<pii> q1,q2;
 29 bool inq[N][N];
 30 int f[N][N][10][10];
 31 pii dfs(int x,int y,int k){
 32     if (vis[x][y][k]==ti) return (pii){0,0};
 33     if (vis[x][y][k]) return G[x][y][k];
 34     vis[x][y][k]=ti;
 35     int kk=k;
 36     if (mp[x][y]==2) kk=(k+1)%4;
 37     else if (mp[x][y]==3) kk=(k+3)%4;
 38     int tx=x+fx[kk],ty=y+fy[kk];
 39     if (mp[tx][ty]==0) return G[x][y][k]=(pii){x,y};
 40     return G[x][y][k]=dfs(tx,ty,kk);
 41 }/*
 42 vector<pii>E[N*N];
 43 void count_sort(pii *b,int n,int l,int r){
 44     int mx=0;
 45     rep(i,N*N) E[i].clear();
 46     F(i,1,n){
 47         E[f[b[i].X][b[i].Y][l][r]].pb(b[i]);
 48         mx=max(mx,f[b[i].X][b[i].Y][l][r]);
 49     }
 50     int tot=0;
 51     F(i,0,mx) rep(j,E[i].size())
 52         b[++tot]=E[i][j];
 53 }*/
 54 int l,r;
 55 bool cmp(pii a,pii b){
 56     return f[a.X][a.Y][l][r]<f[b.X][b.Y][l][r];
 57 }
 58 int main(){
 59 #ifndef ONLINE_JUDGE
 60     freopen("robot.in","r",stdin);
 61     freopen("robot.out","w",stdout);
 62 #endif
 63     n=getint(); w=getint(); h=getint();
 64     F(i,1,h){
 65         scanf("%s",s+1);
 66         F(j,1,w){
 67             F(l,1,n) F(r,l,n) f[i][j][l][r]=INF;
 68             if (s[j]==‘x‘) mp[i][j]=0;
 69             else if (s[j]==‘A‘) mp[i][j]=2;
 70             else if (s[j]==‘C‘) mp[i][j]=3;
 71             else if (s[j]==‘.‘) mp[i][j]=1;
 72             else {int t=mp[i][j]=s[j]-‘0‘+10; f[i][j][t-10][t-10]=0;}
 73         }
 74     }
 75 #define FOR F(i,1,h)F(j,1,w)
 76     FOR if (mp[i][j]) rep(k,4) ++ti,dfs(i,j,k);
 77     F(len,1,n)
 78         for(l=1,r=l+len-1;r<=n;l++,r++){
 79             int tot=0;
 80             FOR{
 81                 F(k,l,r-1) f[i][j][l][r]=min(f[i][j][l][r],f[i][j][l][k]+f[i][j][k+1][r]);
 82                 if (f[i][j][l][r]!=INF) b[++tot]=(pii){i,j},inq[i][j]=1;
 83             }
 84 //            count_sort(b,tot,l,r);
 85             sort(b+1,b+tot+1,cmp);
 86             F(i,1,tot) q1.push(b[i]);
 87             while(!q1.empty()||!q2.empty()){
 88                 pii t;
 89                 if (q1.empty()) t=q2.front(),q2.pop();
 90                 else if (q2.empty()) t=q1.front(),q1.pop();
 91                 else{
 92                     pii t1=q1.front(),t2=q2.front();
 93                     if (f[t1.X][t1.Y][l][r]<f[t2.X][t2.Y][l][r]) t=t1,q1.pop();
 94                     else t=t2,q2.pop();
 95                 }
 96                 int x=t.X,y=t.Y,tx,ty; inq[x][y]=0;
 97                 rep(i,4){
 98                     tx=G[x][y][i].X,ty=G[x][y][i].Y;
 99                     if (!tx||!ty) continue;
100                     if (f[tx][ty][l][r]>f[x][y][l][r]+1){
101                         f[tx][ty][l][r]=f[x][y][l][r]+1;
102                         if (!inq[tx][ty]){
103                             inq[tx][ty]=1;
104                             q2.push((pii){tx,ty});
105                         }
106                     }
107                 }
108             }
109         }
110     int ans=INF;
111     FOR ans=min(ans,f[i][j][1][n]);
112     printf("%d\n",ans==INF?-1:ans);
113     return 0;
114 }

3205: [Apio2013]机器人

Time Limit: 15 Sec  Memory Limit: 128 MB
Submit: 237  Solved: 49
[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 号机器人。

n ≤ 9,w ≤ 500且   h ≤ 500

Source

[Submit][Status][Discuss]

时间: 2024-11-06 03:32:25

【BZOJ】【3205】【APIO2013】机器人robot的相关文章

BZOJ 3205 Apio2013 机器人 斯坦纳树

题目大意:给定一张地图,一些地方有障碍物,有k<=9个机器人,可以一推到底,遇到转向器会转向,两个编号相邻的机器人可以合并,求最少推多少次可以全部合并 令f[l][r][i][j]表示在点(i,j)将编号在[l,r]区间内的机器人全部合并的最小推动次数 则有动规方程组: f[l][r][i][j]=min{f[l][r][_i][_j]+1} ( (_i,_j)->(i,j) ) f[l][r][i][j]=min(f[l][temp][i][j]+f[temp+1][r][i][j]) (l

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

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

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

http://www.lydsy.com/JudgeOnline/problem.php?id=3205 历时一天,老子终于把它A了 哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈 因为不懂spfa的优化 以及 数组越界  TAT ┭┮﹏┭┮ 牢骚发完了,题解在下面  (⊙o⊙)… n只有9,很像状压dp dp[l][r][x][y] 表示在(x,y)位置 合成了x-y复合机器人 的最少推动次数 它的转移 存在后效性 所以上 斯坦纳树 自身的转移:dp[l][r][x][y]=min{dp[l

bzoj3205: [Apio2013]机器人

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3205 思路:类似斯坦纳树的想法 但是因为这里的合并必须连号 所以子集枚举就变成了区间合并 说说做法好了 首先记搜搜出每个点向四个方向走一步会到哪里 注意:转向器可能导致机器人一直在里面转出不来,要特判掉 然后设f[l][r][x][y]表示当前合并的机器人是[l,r],合并点是(x,y) 两种转移: 枚举子区间,合并f[l][r][x][y]=min(f[l][mid][x][y],f[m

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

题目描述 VRI(Voltron 机器人学会)的工程师建造了 n 个机器人.任意两个兼容的机 器人站在同一个格子时可以合并为一个复合机器人. 我们把机器人用 1 至 n 编号(n ≤ 9).如果两个机器人的编号是连续的,那 么它们是兼容的,可以合并成一个复合机器人.最初这 n 个机器人各自都只有唯 一的编号.而一个由两个或以上的机器人合并构成的复合机器人拥有两个编号, 分别是构成它的所有机器人中最小和最大的编号. 例如,2 号机器人只可以与 1 号或 3 号机器人合并.若 2 号机器人与 3 号

[Swift]LeetCode1041. 困于环中的机器人 | Robot Bounded In Circle

On an infinite plane, a robot initially stands at (0, 0) and faces north.  The robot can receive one of three instructions: "G": go straight 1 unit; "L": turn 90 degrees to the left; "R": turn 90 degress to the right. The rob

Luogu P3638 [APIO2013]机器人

(类似)斯坦纳树+DP \(f[l][r][i][j]\) 表示已经构成 \([l,r]\) 的机器人,并在点 \((i,j)\) 的最小代价. 预处理出 \(d[i][j][k]\) 表示在点 \((i,j)\) 方向为 \(k\) 时最终能够到达的点. \(f[l][r][i][j]=\min(f[l][k][i][j],f[k+1][r][i][j])\) \(枚举k,f[l][r][X][Y]=\min(f[l][r][X][Y],f[l][r][i][j]+1),(X,Y)表示(i,j

bzoj 3206: [Apio2013]道路费用【最小生成树+并查集】

参考:http://hzwer.com/6888.html 把k条道路权值设为0,和其他边一起跑MST,然后把此时选中的其他边设为必选,在新图中加上必选变缩成k个点,把所有边重标号,枚举k跳边的选取情况,和其他边做MST,建出树,k条边的权值在树上取min #include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int N=300005,inf=1e9; int

一个控制台程序,模拟机器人对话

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace RobotTest { class Program { static void Main(string[] args) { 机器人 robot = new 机器人(); r