BZOJ3205: [Apio2013]机器人

138 篇文章 0 订阅
13 篇文章 0 订阅

卡常卡了好久qwq

可以先用记忆化搜索搜出每个位置往四个方向走会走到哪,注意判走到已经走过的地方避免死循环
f[l][r][i][j]表示在(i,j)合成机器人l~r的最小花费

f[l][r][i][j]=minf[l][r][di][dj]+1di,dj>i,j
f[l][r][i][j]=min(f[l][k][i][j]+f[k+1][j][i][j])
对于第二个转移,我们按长度从小到大dp,处理到f[l,r,i,j]时枚举k就行了
对于第一个转移,本来要用spfa,因为转移的边权都相同,可以bfs
维护两个队列,把初始状态放在第一个队列,拓展出来的状态放进第二个队列,每次取出两个队列的队头比较,用小的去拓展

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1e9
using namespace std;

const int maxn = 505;
const int maxk = 10;
const int maxd = 4;
const int dx[] = {-1,0,1,0};
const int dy[] = {0,1,0,-1};

int n,m,K;
// 11 +1  12 -1
int a[maxn][maxn];

struct point{int x,y;}d[maxn][maxn][maxd],nul;
bool v[maxn][maxn][maxd];
bool cmp(const int &x,const int &y)
{
    if(!x||!y||x>n||y>m||a[x][y]==-1) return false;
    return true;
}
point search(const int x,const int y,int k)
{
    if(v[x][y][k]) return nul;
    if(d[x][y][k].x) return d[x][y][k];

    int tk=k;
    v[x][y][tk]=true;
    if(a[x][y]==11) k=(k+1)%maxd;
    if(a[x][y]==12) k=(k+3)%maxd;
    int nx=x+dx[k],ny=y+dy[k];
    if(!cmp(nx,ny)) d[x][y][tk]=(point){x,y};
    else d[x][y][tk]=search(nx,ny,k);
    v[x][y][tk]=false;
    return d[x][y][tk];
}

struct node{int x,y,d;}t[maxn*maxn]; int tp;
queue<node>q1,q2; int h1,h2;
inline bool cmpt(const node x,const node y){return x.d<y.d;}
int f[maxk][maxk][maxn][maxn];

char str[maxn];

int main()
{
    nul.x=nul.y=-1;
    scanf("%d%d%d",&K,&m,&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%s",str);
        for(int j=1;j<=m;j++)
        {
            char cc=str[j-1];
            if(cc=='x') a[i][j]=-1;
            else if(cc=='.') a[i][j]=0;
            else if(cc=='A') a[i][j]=12;
            else if(cc=='C') a[i][j]=11;
            else a[i][j]=cc-'0';
        }
    }
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) for(int k=0;k<maxd;k++) d[i][j][k].x=d[i][j][k].y=0;
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++)
    {
        for(int k=0;k<maxd;k++) if(d[i][j][k].x==0) 
            d[i][j][k]=search(i,j,k);
    }

    for(int l=1;l<=K;l++) for(int r=1;r<=K;r++) for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) f[l][r][i][j]=-1;
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(a[i][j]>0&&a[i][j]<10)
        f[a[i][j]][a[i][j]][i][j]=0;
    for(int L=1;L<=K;L++)
    {
        for(int l=1;l+L-1<=K;l++)
        {
            int r=l+L-1;

            tp=0;
            for(int k=l;k<r;k++) for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(a[i][j]!=-1)
            {
                int &tmp=f[l][r][i][j];
                if(f[l][k][i][j]!=-1&&f[k+1][r][i][j]!=-1)
                {
                    int temp=f[l][k][i][j]+f[k+1][r][i][j];
                    if(tmp==-1||tmp>temp) tmp=temp;
                }
            }
            for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(f[l][r][i][j]!=-1)
                t[++tp]=(node){i,j,f[l][r][i][j]};
            sort(t+1,t+tp+1,cmpt);
            for(int i=1;i<=tp;i++) q1.push(t[i]);
            h1=h2=inf;
            if(!q1.empty()) h1=(q1.front()).d;
            while(h1!=inf||h2!=inf)
            {
                if(h1<=h2)
                {
                    node now=q1.front(); q1.pop();
                    int x=now.x,y=now.y;
                    if(f[l][r][x][y]==h1)
                    {
                        for(int k=0;k<maxd;k++) if(d[x][y][k].x!=-1)
                        {
                            int nx=d[x][y][k].x,ny=d[x][y][k].y,&kk=f[l][r][nx][ny];
                            if(kk==-1||kk>h1+1)
                            {
                                kk=h1+1;
                                q2.push((node){nx,ny,kk});
                            }
                        }
                    }
                }
                else
                {
                    node now=q2.front(); q2.pop();
                    int x=now.x,y=now.y;
                    if(f[l][r][x][y]==h2)
                    {
                        for(int k=0;k<maxd;k++) if(d[x][y][k].x!=-1)
                        {
                            int nx=d[x][y][k].x,ny=d[x][y][k].y,&kk=f[l][r][nx][ny];
                            if(kk==-1||kk>h2+1)
                            {
                                kk=h2+1;
                                q2.push((node){nx,ny,kk});
                            }
                        }
                    }
                }
                h1=h2=inf;
                if(!q1.empty()) h1=(q1.front()).d;
                if(!q2.empty()) h2=(q2.front()).d;
            }

        }
    }
    int re=-1;
    for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(f[1][K][i][j]!=-1)
        if(re>f[1][K][i][j]||re==-1) re=f[1][K][i][j];
    printf("%d\n",re);

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值