題解 P2937 【[USACO09JAN]激光電話Laserphones】
阿新 • • 發佈:2019-05-02
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】