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,k)最终到达的点\)

spfa 要优化:用两个队列,一个存初始状态(先排完序再扔进去),一个存扩展出来的状态,每次取两个队头中较小的去扩展。

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstring>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
  register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
  do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int N=10,M=510,Inf=0x3f3f3f3f;
const int dx[]={-1,0,1,0},dy[]={0,-1,0,1};
struct node { int x,y,dis;
    inline bool operator < (const node& that) const
        {return dis<that.dis;}
};
int n,h,w,ans=Inf;
int d[M][M][4],f[N][N][M][M];
char s[M][M];
bool vis[M][M][4],inq[M][M];
#define P(i,j) ((i-1)*w+j)
inline int dfs(int i,int j,int k) {
  if(i<1||i>h||j<1||j>w) return 0;
  if(s[i][j]=='x') return 0;
  if(d[i][j][k]) return d[i][j][k];
  if(vis[i][j][k]) return -1;
  vis[i][j][k]=true; R K=k;
  if(s[i][j]=='A') K=(k+1)%4;
  if(s[i][j]=='C') K=(k+3)%4;
    d[i][j][k]=dfs(i+dx[K],j+dy[K],K);
  if(!d[i][j][k]) d[i][j][k]=P(i,j);
  vis[i][j][k]=false;
  return d[i][j][k];
}
queue<node> q1,q2;
vector<node> mem;
inline void main() {
  n=g(),w=g(),h=g();
  for(R i=1;i<=h;++i) scanf("%s",s[i]+1);
  for(R i=1;i<=h;++i) for(R j=1;j<=w;++j)
    for(R k=0;k<4;++k) d[i][j][k]=dfs(i,j,k);
  memset(f,0x3f,sizeof f);
  for(R i=1;i<=h;++i) for(R j=1;j<=w;++j)
    if(isdigit(s[i][j]))
      f[s[i][j]-'0'][s[i][j]-'0'][i][j]=0;
  for(R l=n;l>=1;--l) for(R r=l;r<=n;++r) {
    for(R i=1;i<=h;++i) for(R j=1;j<=w;++j) for(R k=l;k<r;++k)
      f[l][r][i][j]=min(f[l][r][i][j],f[l][k][i][j]+f[k+1][r][i][j]);
    for(R i=1;i<=h;++i) for(R j=1;j<=w;++j)
      if(f[l][r][i][j]!=Inf)
        mem.push_back((node){i,j,f[l][r][i][j]}),inq[i][j]=true;
    sort(mem.begin(),mem.end());
    for(const auto& v:mem) q1.push(v); mem.clear();
    while(q1.size()||q2.size()) {
      R x,y;
      if(q1.size()) {
        if(q2.size()) {
          if(f[l][r][q1.front().x][q1.front().y]<f[l][r][q2.front().x][q2.front().y])
            x=q1.front().x,y=q1.front().y,q1.pop();
          else
            x=q2.front().x,y=q2.front().y,q2.pop();
        } else
                x=q1.front().x,y=q1.front().y,q1.pop();
      }
            else x=q2.front().x,y=q2.front().y,q2.pop();
            inq[x][y]=false;
      for(R k=0;k<4;++k) {
        R xx=(d[x][y][k]-1)/w+1,yy=(d[x][y][k]-1)%w+1;
        if(f[l][r][xx][yy]>f[l][r][x][y]+1) {
          f[l][r][xx][yy]=f[l][r][x][y]+1;
          if(!inq[xx][yy]) {
            q2.push((node){xx,yy,f[l][r][xx][yy]});
            inq[xx][yy]=true;
          }
        }
      }
    }
  }
  for(R i=1;i<=h;++i) for(R j=1;j<=w;++j)
    ans=min(ans,f[1][n][i][j]);
  if(ans==Inf) puts("-1");
  else printf("%d\n",ans);
}
} signed main() {Luitaryi::main(); return 0;}


2020.01.18

原文地址:https://www.cnblogs.com/Jackpei/p/12209865.html

时间: 2024-11-02 10:59:44

Luogu P3638 [APIO2013]机器人的相关文章

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

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

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

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

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

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

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

luogu P4012 深海机器人问题

费用流问题,每个样本选一次,就连一条capacity为1,权为给定的值,因为可以重复走,再连capacity为无穷,权为0的边,再一次连接给定的出点和汇点即可 #include<bits/stdc++.h> using namespace std; #define lowbit(x) ((x)&(-x)) typedef long long LL; const int maxm = 3e3+5; const int INF = 0x3f3f3f3f; struct edge{ int

【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]

luogu P1126 机器人搬重物

题目描述 机器人移动学会(RMI)现在正尝试用机器人搬运物品.机器人的形状是一个直径1.6米的球.在试验阶段,机器人被用于在一个储藏室中搬运货物.储藏室是一个N*M的网格,有些格子为不可移动的障碍.机器人的中心总是在格点上,当然,机器人必须在最短的时间内把物品搬运到指定的地方.机器人接受的指令有:向前移动1步(Creep):向前移动2步(Walk):向前移动3步(Run):向左转(Left):向右转(Right).每个指令所需要的时间为1秒.请你计算一下机器人完成任务所需的最少时间. 输入输出格

洛谷—— P1126 机器人搬重物

https://www.luogu.org/problem/show?pid=1126 题目描述 机器人移动学会(RMI)现在正尝试用机器人搬运物品.机器人的形状是一个直径1.6米的球.在试验阶段,机器人被用于在一个储藏室中搬运货物.储藏室是一个N*M的网格,有些格子为不可移动的障碍.机器人的中心总是在格点上,当然,机器人必须在最短的时间内把物品搬运到指定的地方.机器人接受的指令有:向前移动1步(Creep):向前移动2步(Walk):向前移动3步(Run):向左转(Left):向右转(Righ