【USACO-水桶传递队列】三种角度深刻理解
问题描述
农场上起火了,奶牛们正在紧急赶去灭火!农场可以用一个像这样的 10×10 的字符方阵来描述:................................B......................R.............................L..............字符’B’表示正着火的牛棚,字符’L’表示一个湖,而字符’R’表示农场上的一块巨大岩石。奶牛们想要沿着一条湖到牛棚之间的路径组成一条“水桶传递队列”,这样她们就可以沿着这条路径传递水桶来帮助灭火。当两头奶牛在东南西北四个方向上相邻时水桶可以在她们之间传递。湖边的奶牛也是如此——奶牛只能在紧挨着湖的时候才能用水桶从湖里取水。类似地,奶牛只能在紧挨着牛棚的时候才能用水去灭牛棚的火。请帮助求出奶牛们为了组成这样的“水桶传递队列”需要占据的’.’格子的最小数量。奶牛不能站在岩石所在的方格之内,此外保证牛棚和湖不是相邻的。输入格式输入包含 10 行,每行 10 个字符,描述这个农场的布局。输入保证图案中恰有一个字符’B’、一个字符’L’以及一个字符’R’。输出格式输出一个整数,为组成一条可行的水桶传递队列所需要的奶牛的最小数量。输入样例:................................B......................R.............................L..............输出样例:7样例解释在这个例子中,以下是一个可行的方案,使用了最小数量的奶牛(7):................................B.........C.........CC.R.......CCC.........C.........L..............
思路分析
一看好像是道经典的搜索题目。大概率要用bfs,我在最开始尝试了一下dfs,不过一直爆栈或者tle。最后根据找到的性质进行了剪枝。后面又尝试了下bfs。最后发现其实也可以是分类讨论
一、DFS
#include using namespace std;char g[20][20];bool b[20][20];int ne[5][3]= {{0,1},{1,0},{0,-1},{-1,0}};/偏移量int sx,sy;//牛棚的位置int ex,ey;//湖的位置int tx,ty;//石子的位置int t;//标记三者是否在同一条直线上int res=1e8;void dfs(int x,int y,int step){ if(step>abs(ey-sy)+abs(ex-sx)+t)//剪枝 return; if(x==ex&&y==ey)//如果到了终点,更新 { res=min(step,res); return; } for(int k=0; k=0&&t1=0&&t2<10&&g[t1][t2]!='R'&&!b[t1][t2]) { b[t1][t2]=1; dfs(t1,t2,step+1); b[t1][t2]=0; } }}int main(){ for(int i=0; i<10; i++) for(int j=0; j>g[i][j]; if(g[i][j]=='B') sx=i,sy=j; if(g[i][j]=='L') ex=i,ey=j; if(g[i][j]=='R') tx=i,ty=j; } if(ty==sy&&ty==ey||tx==sx&&tx==ex)//特判一下是不是三者在一条直线上 t=2; b[sx][sy]=1; dfs(sx,sy,0); cout<<res-1;//减1是因为把终点也算了进去 return 0;}
二、BFS
#include #include #include #include #include using namespace std;typedef pair PII;char g[20][20];int d[20][20];bool st[20][20];int ne[5][3]={{0,1},{1,0},{0,-1},{-1,0}};int n=10,m=10;int x1,y1,x2,y2;int bfs(){ queue q; q.push({x1,y1}); memset(d,-1,sizeof d); d[x1][y1]=0; while(q.size()) { auto t=q.front(); q.pop(); for(int k=0;k=0&&x=0&&y<m&&d[x][y]==-1&&!st[x][y]&&g[x][y]!='R') { q.push({x,y}); d[x][y]=d[t.first][t.second]+1; } } } return d[x2][y2];}int main(){ for(int i=0;i<n;i++) for(int j=0;j>g[i][j]; if(g[i][j]=='L') x2=i,y2=j; else if(g[i][j]=='B') x1=i,y1=j; } st[x1][y1]=true; cout<<bfs()-1; return 0;}
三、分类讨论
#include //分类讨论using namespace std;int main(){ int x1,y1,x2,y2,x3,y3; for(int i=0;i<10;i++) { for(int j=0;j>x; if(x=='B') x1=i,y1=j; else if(x=='R') x2=i,y2=j; else if(x=='L') x3=i,y3=j; } } int res=abs(x3-x1)+abs(y3-y1); if(x1==x2&&x2==x3&&(y2-y1)*(y2-y3)<0||y1==y2&&y1==y3&&(x2-x1)*(x2-x3)<0) res+=2; cout<<res-1; return 0;}