(intermediate) UVA 最短路 10798 - Be wary of Roses



  Be Wary of Roses 

You've always been proud of your prize rose garden. However, some jealous fellow gardeners will stop at nothing to gain an edge over you. They have kidnapped, blindfolded, and handcuffed you, and dumped you right in the middle of your treasured roses! You need to get out, but you're not sure you can do it without trampling any precious flowers.

\epsfbox{p10798.eps}

Fortunately, you have the layout of your garden committed to memory. It is an N×Ncollection of square plots (N odd), some containing roses. You are standing on a square marble plinth in the exact center. Unfortunately, you are quite disoriented, and have no idea which direction you're facing! Thanks to the plinth, you can orient yourself facing one of NorthEastSouth, or West, but you have no way to know which.

You must come up with an escape path that tramples the fewest possible roses, no matter which direction you're initially facing. Your path must start in the center, consist only of horizontal and vertical moves, and end by leaving the grid.

Input 

Every case begins with N, the size of grid ( 1$ \le$N$ \le$21), on a line. N lines with N characters each follow, describing the garden: `.' indicates a plot without any roses, `R' indicates the location of a rose, and `P' stands for the plinth in the center.

Input will end on a case where N = 0. This case should not be processed.

Output 

For each case, output a line containing the minimum guaranteed number of roses you can step on while escaping.

Sample Input 

5
.RRR.
R.R.R
R.P.R
R.R.R
.RRR.
0

Sample Output 

At most 2 rose(s) trampled.



Problem setter: Derek Kisman
Special Thanks: Md. Kamruzzaman

Miguel Revilla 2004-12-10




题意:你被困在一个花园里面,你不知道你正在朝向的方位,但是你能够向前走、向右走、向后走或者向左走。而且花园里面有些地方会有鲜花,你是一个热爱花朵的人,你不希望践踏花朵,但是为了逃出去,可能不得踩死一些,现在就要你找出一个行走的方案。(即向前->向后。。。。)这个方案能让你践踏尽量少的的花并逃出去。 


思路:由于一个行走方案对应着四条行走的路线。那么这个方案损坏的花的数目应该等于四条路线中毁坏花朵最多的路线。我们要的是最小值。我们能想到用最短路来进行搜索。。。。但是状态怎么表示呢?对于一个方案我们要记录每条路线毁掉的花朵的数目,并且要记住他们的位置以及方向。。。。那么维数不就很多吗? 你随便找一个方案走走看,你会方向有很多地方时对称的,位置的状态我们只需要取一个就行了,根据这一个位置我们就能求出其他的路线在当前对应的位置,方向的话我们只需要记录两个路线的方向就行了,这两条路线是不关于中心对称的。那么其余两条路线的位置和方向都是唯一确定的。接下来我们再用4维表示四条路线的毁花值?我们只需要三维,另外的一个毁花值我们用类似最短路的做法来求,这样就能减少一维了。。。。我觉得应该还有更好的表示方法。。。注意N只有21,也就是说毁花值最多也就是10,我们一直往前走,最多只需要走10个格子就出去了,自然花朵最多也就毁掉10个。所以我们有一个d[23*23][4][4][11][11][11] 的数组。。。。其实这个也不小了。。。都有10^7了。所以我觉得会有更好的办法。接下来我们用优先队列按照每个状态的四条路的最大毁花值排序来进行搜。。。当第一次遇到的状态时已经逃出去了,那么就有答案了。


代码:

#include<iostream>
#include<cstdio>
#include<string.h>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
const int maxn=23+5;
int n,center;
const int Move[2][4]={{-1,0,1,0},{0,1,0,-1} };
inline int max(int a,int b) { return a>b? a:b; }
inline int getx(int r,int c) { return r*(n+2)+c; }
inline int row(int x) { return x/(n+2); }
inline int col(int x) { return x%(n+2); }
inline bool inRange(int r,int c) { return 0<r&&r<=n&&0<c&&c<=n; }
inline bool inRange(int x) { return 0<row(x)&&row(x)<=n&&0<col(x)&&col(x)<=n; }
short vis[maxn*maxn][4][4][11][11][11];
char maze[maxn][maxn];

struct State
{
    int x[4];
    int cost[4];
    int dir[4];
    int maxcost;
    void setMaxcost()
    {
        maxcost=max(cost[0],max(cost[1],max(cost[2],cost[3])));
    }

    bool ok() const
    {
        for(int i=0;i<4;++i)
            if(inRange(x[i])) return false;
        return true;
    }
    bool operator<(const State&st) const
    {
        return maxcost > st.maxcost;
    }
    State()
    {
        for(int i=0;i<4;++i)
        {
            x[i]=center;
            cost[i]=0;
            dir[i]=i;
        }
        maxcost=0;
    }
};

void input()
{
    memset(maze,0,sizeof(maze));
    center=-1;
    for(int i=1;i<=n;++i)
    {
        scanf("%s",maze[i]+1);
        for(int j=0;j<n;++j)
        if(maze[i][j+1]=='P') center=getx(i,j+1);
    }
}

inline void setvis(int x,int dir1,int dir2,int c2,int c3,int c4,int c)
{
    vis[x][dir1][dir2][c2][c3][c4]=c;
}

inline int invis(int x,int dir1,int dir2,int c2,int c3,int c4)
{
    return vis[x][dir1][dir2][c2][c3][c4];
}

void solve()
{
    memset(vis,0x3f,sizeof(vis));
    priority_queue<State> q;
    State start;
    for(int i=0;i<4;++i)
    {
        start.x[i]=center;
        start.dir[i]=i;
        start.maxcost=0;
    }
    setvis(center,0,1,0,0,0,0);
    q.push(start);
    State now;
    int r[4],c[4],rr[4],cc[4],dir1[4],dir2[4],costx[4],costy[4];
    int x[4],y[4];
    int ans=1e8;
    while(q.size())
    {
        State tmp=q.top(); q.pop();
        if(tmp.ok())
        {
           ans=tmp.maxcost;
           break;
        }
        for(int i=0;i<4;++i)
        {
            r[i]=row(tmp.x[i]);
            c[i]=col(tmp.x[i]);
     //       printf("%d %d\n",r[i],c[i]);
            dir1[i]=tmp.dir[i];
            costx[i]=tmp.cost[i];
            x[i]=tmp.x[i];
        }
        //四个方向
        for(int i=0;i<4;++i)
        {
            for(int j=0;j<4;++j)
            {
                rr[j]=r[j];
                cc[j]=c[j];
                dir2[j]=dir1[j];
                costy[j]=costx[j];
                y[j]=x[j];
                if(!inRange(r[j],c[j]))  continue;
                rr[j]+=Move[0][(i+dir1[j])%4];
                cc[j]+=Move[1][(i+dir1[j])%4];
                dir2[j]=(i+dir1[j])%4;
                y[j]=getx(rr[j],cc[j]);
                if(inRange(rr[j],cc[j])&&maze[rr[j]][cc[j]]=='R') ++costy[j];
            }
            for(int j=0;j<4;++j)
            {
                now.x[j]=y[j];
                now.cost[j]=costy[j];
                now.dir[j]=dir2[j];

            }
            now.setMaxcost();
            if(now.maxcost>n/2) continue;
//            printf("%d %d\n%d %d\n%d %d\n%d %d\n",rr[0],cc[0],rr[1],cc[1],rr[2],cc[2],rr[3],cc[3]);
//            printf("%d %d %d %d\n",costy[0],costy[1],costy[2],costy[3]);
            if(invis(y[0],dir2[0],dir2[1],costy[1],costy[2],costy[3])<=now.cost[0]) continue;
            setvis(y[0],dir2[0],dir2[1],costy[1],costy[2],costy[3],now.cost[0]);
            q.push(now);
        }
    }
    printf("At most %d rose(s) trampled.\n",ans);
}

int main()
{
    while(scanf("%d",&n)==1)
    {
        if(n==0) return 0;
        input();
        solve();
    }
    return 0;
}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值