1. 程式人生 > >題解 P2937 【[USACO09JAN]激光電話Laserphones】

題解 P2937 【[USACO09JAN]激光電話Laserphones】

pac 光電 front getchar truct 存在 更新 我們 否則

看到這題,一下就想到了爆搜。(不過這題輸入也是夠坑的)

單純的搜索肯定是會超時的,所以這裏需要考慮一些剪枝。

我們令bin[i][j][k]為在第i行j列時,方向為k的最小鏡子數,若當時的鏡子數已大於或等於此記錄,那麽就不必要更新了

否則往該點的四個方向進行更新:

  • 方向相同

沒必要放鏡子了

  • 方向相反

不存在這種可能,忽略(否則你的鏡子要怎麽放呢?)

  • 其他

放一面鏡子,更新方向

BFS代碼:

#include<bits/stdc++.h>
using namespace std;
const int MAXN=100+10;
char Map[MAXN][MAXN];
int n,m;
int bx,by,ex,ey;
int dx[5]={0,0,1,0,-1};
int dy[5]={0,1,0,-1,0};
int ans=0x3f3f3f3f;
int bin[MAXN][MAXN][5];//剪枝用
struct Node
{
    int x,y;
    int cnt;
    int dir;//表示的方向
    /*
    1:right
    2:down
    3:left
    4:up
    */
};
inline int read()
{
    int tot=0;
    char c=getchar();
    while(c<'0'||c>'9')
        c=getchar();
    while(c>='0'&&c<='9')
    {
        tot=tot*10+c-'0';
        c=getchar();
    }
    return tot;
}
inline void BFS()
{
    queue<Node>q;
    q.push((Node){bx,by,0,1});//推四種方向到隊列中
    q.push((Node){bx,by,0,2});
    q.push((Node){bx,by,0,3});
    q.push((Node){bx,by,0,4});
    bin[bx][by][1]=bin[bx][by][2]=bin[bx][by][3]=bin[bx][by][4]=0;
    while(q.size())
    {
        Node now=q.front();
        //cout<<now.x<<" "<<now.y<<" "<<now.cnt<<" "<<now.dir<<endl;
        q.pop();
        if(now.cnt>=ans)continue;
        if(now.x==ex&&now.y==ey)
        {
            ans=min(ans,now.cnt);//更新答案
            continue;//註意:這裏不能用break
        }
        for(int i=1;i<=4;i++)
        {
            int a=dx[i]+now.x,b=dy[i]+now.y;
            if(a<1||b<1||a>n||b>m)continue;
            if(now.cnt>=bin[a][b][i])continue;//沒必要更新了
            if(Map[a][b]=='*')continue;
            if(now.dir==i)
            {
                q.push((Node){a,b,now.cnt,i});
                bin[a][b][i]=now.cnt;//更新最小值
            }
            else 
            {
                if(now.dir+i==4)continue;//這是方向相反時,看不懂的回去看一下各個數字代表的方向
                q.push((Node){a,b,now.cnt+1,i});
                bin[a][b][i]=now.cnt+1;//更新最小值
            }
        }
    }
}
int main()
{
    m=read();n=read();
    memset(bin,0x3f3f3f3f,sizeof(bin));//賦初值
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            cin>>Map[i][j];
            if(Map[i][j]=='C'&&!bx&&!by)bx=i,by=j;//尋找起點
            else if(Map[i][j]=='C')ex=i,ey=j;//尋找終點
        }
    }
    BFS();
    /*for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            for(int k=1;k<=4;k++)cout<<bin[i][j][k]<<" ";
            cout<<endl;
        }
        cout<<endl<<endl;
    }*/
    cout<<ans<<endl;
    return 0;
}

題解 P2937 【[USACO09JAN]激光電話Laserphones】