原题链接:https://vjudge.net/problem/POJ-1321
题意: 中文题目就不翻译了。
思路: 用 vis[i] 数组来标记第 i 列是否放有棋子,sum 表示已放入多少个棋子,ans 表示方案数,从第一行开始深搜,当放入的棋子数等于给定需要放入的棋子数时,方案数加 1 并返回。当所搜索行数超出棋盘,也返回。
注意: 因为是多组输入,所以计数的变量在每次循环开始前要初始化为0。
Code(C++):
#include
#include
using namespace std;
int n,k; //n表示棋盘行列,k表示要放入的棋子数
int vis[10]; //标记第i列是否已放有棋子
int ans; //方案数
int sum; //已放入的棋子数
char ch[10][10];
void dfs(int x){
if(sum==k){ //当放入的棋子数等于给定需要放入的棋子数时,方案数加1
ans++;
return;
}
if(x>n) //当所搜索的行数大于棋盘时,直接返回
return;
for(int i=1;i<=n;i++){ //搜索每一列
if(!vis[i] && ch[x][i]=='#'){
vis[i]=1;
sum++;
dfs(x+1); //回溯
vis[i]=0;
sum--;
}
}
dfs(x+1);
}
int main(){
while(cin>>n>>k){
if(n==-1 && k==-1)
break;
ans=0,sum=0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>ch[i][j];
dfs(1); //从第一行开始搜索
cout<<ans<<endl;
}
return 0;
}
原题链接:https://vjudge.net/problem/POJ-3984
题意: 给一个迷宫地图,1 表示墙壁,0 表示通道,只能横着走或者竖着走,求从左上角到右上角的最短路径。
思路: 求最短路径一般就是广度优先搜索,定义结构体pre[x][y],表示该点的前一个元素,即保存路径。从左上角(0, 0)位置开始搜索,分别向上下左右搜索,已走过的点标记为1,未走过且可以走的点压入队列,最后当搜索到终点的时候,再把队列里的路径从头到尾一个个递归输出。
C++ Code:
#include
#include
#define ll long long
using namespace std;
const int N=1e6+5;
int cnt;
int vis[10][10],maps[10][10];
int dir_x[4]={0,0,1,-1};
int dir_y[4]={1,-1,0,0};
struct node{
int x,y;
};
node pre[10][10];
void out(node cur){
if(cur.x==0 && cur.y==0){
cout<<"("<<cur.x<<", "<<cur.y<<")"<<endl;
return;
}
out(pre[cur.x][cur.y]);
cout<<"("<<cur.x<<", "<<cur.y<<")"<<endl;
}
void bfs(){
queue<node> q;
node start;
start.x=0,start.y=0;
q.push(start);
vis[0][0]=1;
while(!q.empty()){
node now = q.front();
q.pop();
if(now.x==4 && now.y==4){
out(now);
return;
}
for(int i=0;i<4;i++){
node next;
next.x=now.x+dir_x[i];
next.y=now.y+dir_y[i];
if(next.x>=0 && next.x<5 && next.y>=0 && next.y<5 && !vis[next.x][next.y] && !maps[next.x][next.y]){
vis[next.x][next.y]=1;
q.push(next);
pre[next.x][next.y]=now;
}
}
}
}
int main(){
for(int i=0;i<5;i++)
for(int j=0;j<5;j++)
cin>>maps[i][j];
bfs();
return 0;
}
Java Code:
import java.util.Scanner;
class node{
int x,y,pre;
public node() {}
public node(int x,int y,int pre) {
this.x=x;
this.y=y;
this.pre=pre;
}
}
public class Main {
static int front=0,rear=1;
static int[][] dir = {{1,0},{-1,0},{0,1},{0,-1}};
static int[][] maps = new int[10][10];
static node[] q = new node[100];
static void print(int index) {
if(q[index].pre!=-1) {
print(q[index].pre);
System.out.println("("+q[index].x+", "+q[index].y+")");
}
}
static void bfs(int x,int y) {
q[front]= new node(x,y,-1);
while(front<rear) {
for(int i=0;i<4;i++) {
for(int j=0;j<4;j++) {
int xx=q[front].x+dir[i][0];
int yy=q[front].y+dir[i][1];
if(xx<0||xx>4||yy<0||yy>4||maps[xx][yy]!=0)
continue;
maps[xx][yy]=1;
q[rear] = new node(xx,yy,front);
if(xx==4&&yy==4) print(rear);
rear++;
}
}
front++;
}
}
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
for(int i=0;i<5;i++)
for(int j=0;j<5;j++)
maps[i][j]=cin.nextInt();
for(int i=0;i<100;i++) //结构体要全部初始化,不然搜索时会报空指针异常
q[i]=new node();
System.out.println("(0, 0)");
bfs(0,0);
}
}
原题链接:https://vjudge.net/problem/POJ-2251
题意: 一个三维的迷宫题目,其中用‘.’表示空地,‘#’表示障碍物,‘S’表示起点,‘E’表示终点,可以上下左右前后移动,每次都只能移到相邻的空位,每次需要花费一分钟,求从起点到终点最少要多久。
思路: 做法跟迷宫问题差不多,就是从二维变为三维。
C++ Code:
#include
#include
#include
using namespace std;
int l,r,c;
char ch[50][50][50];
int vis[50][50][50];
int dir[6][3]={{1,0,0},{-1,0,0},{0,1,0},{0,-1,0},{0,0,1},{0,0,-1}};
struct node{
int x,y,z,step;
};
void bfs(int sl,int sr,int sc,int el,int er,int ec){
memset(vis,0,sizeof(vis));
queue<node> q;
node start;
start.x=sl, start.y=sr, start.z=sc, start.step=0;
vis[sl][sr][sc]=1;
q.push(start);
int flag=0;
while(!q.empty()){
node now = q.front();
q.pop();
if(now.x==el && now.y==er && now.z==ec){
flag=1;
cout<<"Escaped in "<<now.step<<" minute(s)."<<endl;
return;
}
for(int i=0;i<6;i++){
node next;
next.x=now.x+dir[i][0];
next.y=now.y+dir[i][1];
next.z=now.z+dir[i][2];
next.step=now.step+1;
if(next.x>=1 && next.x<=l && next.y>=1 && next.y<=r && next.z>=1 && next.z<=c && !vis[next.x][next.y][next.z] && ch[next.x][next.y][next.z]=='.'){
vis[next.x][next.y][next.z]=1;
q.push(next);
}
}
}
if(!flag) cout<<"Trapped!"<<endl;
}
int main(){
while(cin>>l>>r>>c && l && r && c){
for(int i=1;i<=l;i++)
for(int j=1;j<=r;j++)
for(int k=1;k<=c;k++)
cin>>ch[i][j][k];
int sl,sr,sc,el,er,ec;
for(int i=1;i<=l;i++){
for(int j=1;j<=r;j++){
for(int k=1;k<=c;k++){
if(ch[i][j][k]=='S'){ //记录入口
sl=i;
sr=j;
sc=k;
}else if(ch[i][j][k]=='E'){ //记录出口
el=i;
er=j;
ec=k;
ch[i][j][k]='.'; //出口也是能走的,记得转换
}
}
}
}
bfs(sl,sr,sc,el,er,ec);
}
return 0;
}
Java Code:
import java.util.Scanner;
class node{
int x,y,z,step;
public node() {}
public node(int x,int y,int z,int step) {
this.x=x;
this.y=y;
this.z=z;
this.step=step;
}
}
public class Main {
static int l,r,c,sx,sy,sz;
static int front,rear;
static boolean flag;
static boolean[][][] vis = new boolean[50][50][50];
static char[][][] maps = new char[50][50][50];
static int[][] dir = {{1,0,0},{-1,0,0},{0,1,0},{0,-1,0},{0,0,1},{0,0,-1}};
static node[] q = new node[300000];
static void bfs(int sx,int sy,int sz) {
front=1; rear=2;
vis[sx][sy][sz]=true;
q[front]=new node(sx,sy,sz,0);
while(front<rear) {
int x = q[front].x;
int y = q[front].y;
int z = q[front].z;
if(maps[x][y][z]=='E') {
flag=true;
System.out.println("Escaped in " + q[front].step + " minute(s).");
return;
}
for(int i=0;i<6;i++) {
int xx = x+dir[i][0];
int yy = y+dir[i][1];
int zz = z+dir[i][2];
if(xx>=1 && xx<=l && yy>=1 && yy<=r && zz>=1 && zz<=c && maps[xx][yy][zz]!='#' && !vis[xx][yy][zz]) {
vis[xx][yy][zz]=true;
q[rear] = new node(xx,yy,zz,q[front].step+1);
rear++;
}
}
front++;
}
if(!flag) System.out.println("Trapped!");
}
public static void main(String[] args) {
Scanner cin = new Scanner(System.in);
while(cin.hasNext()) {
flag=false;
for(int i=0;i<50;i++)
for(int j=0;j<50;j++)
for(int k=0;k<50;k++)
vis[i][j][k]=false;
l=cin.nextInt(); r=cin.nextInt(); c=cin.nextInt();
if(l==0 && r==0 && c==0) break;
for(int i=1;i<=l;i++)
for(int j=1;j<=r;j++) {
String str = cin.next();
for(int k=1;k<=c;k++) {
maps[i][j][k]=str.charAt(k-1);
if(maps[i][j][k]=='S') {
sx=i; sy=j; sz=k;
}
}
}
bfs(sx,sy,sz);
}
}
}
原题链接: https://vjudge.net/problem/POJ-3278
题意: 农夫追牛,牛不动,农夫有三种移动方式,第一种:向前移动一步;第二种:向后移动一步;第三种:农夫现在的位置乘以2;每次移动都消耗1分钟,求农夫追到牛的最短时间。
思路: 求最短时间,可知要用bfs。从农夫的位置出发,分别把三种方法列出来,不断的广搜,同时更新所用的时间并存入数组,直到到达牛的位置k。
Code(C++):
#include
#include
using namespace std;
const int N=1e6;
int ans[N+10],vis[N+10];
queue<int> q;
void bfs(int n,int k){
int pos=0;
if(n==k) return;
q.push(n);
while(!q.empty()){
pos=q.front();
q.pop();
if(pos+1<=N && vis[pos+1]==0){ //向右移动一步
ans[pos+1]=ans[pos]+1;
vis[pos+1]=1;
q.push(pos+1);
}
if(pos+1==k) break;
if(pos-1>=0 && vis[pos-1]==0){ //向左移动一步
ans[pos-1]=ans[pos]+1;
vis[pos-1]=1;
q.push(pos-1);
}
if(pos-1==k) break;
if(pos*2<=N && vis[pos*2]==0){ //位置乘以2
ans[pos*2]=ans[pos]+1;
vis[pos*2]=1;
q.push(pos*2);
}
if(pos*2==k) break;
}
}
int main(){
int n,k;
cin>>n>>k;
bfs(n,k);
cout<<ans[k]<<endl;
return 0;
}
原题链接: https://vjudge.net/problem/POJ-1426
题意: 输入一个200以内的正整数 n,求 n 的倍数 m 且要求 m 只由0、1组成,得到的答案的位数在100以内。符合条件的任意答案都可以。
思路: 可以用STL的queue来做,不断地广搜n的倍数,一找到就输出。
Code(C++):
#include
#include
using namespace std;
typedef long long ll;
void bfs(int n){
queue<ll> q;
q.push(1);
while(!q.empty()){
ll x=q.front();
q.pop();
ll ans=x*10;
if(ans%n==0){
cout<<ans<<endl;
return;
}
q.push(ans);
ans=x*10+1;
if(ans%n==0){
cout<<ans<<endl;
return;
}
q.push(ans);
}
}
int main(){
int n;
while(cin>>n && n){
bfs(n);
}
return 0;
}
原题链接: https://vjudge.net/problem/POJ-3126
题意: 给定两个素数 n 和 m,要求把 n 变成 m,每次变换时只能变一个数字,即变换后的数与变换前的数只有一个数字不同,并且要保证变换后的四位数也是素数。求最小的变换次数。如果不能完成变换,输出Impossible。
思路: 求最小变换次数,可知是用BFS,只要一找到就保证了变换次数最少。个位数是偶数的一定不是奇数,所以各位只能是奇数。千位数不能为0。所以对每个数位进行枚举,符合条件的话,就入队,并且标记已用过,直到变换成功。
Code(C++):
#include
#include
#include
using namespace std;
int n,m;
int vis[10010];
struct node{
int x; //表示某数
int step; //表示路径数
};
queue<node> q;
bool isPrime(int x){ //判断是否为素数
if(x==0||x==1) return false;
for(int i=2;i*i<=x;i++){
if(x%i==0) return false;
}
return true;
}
void bfs(){
while(!q.empty()){
node t=q.front();
q.pop();
int x0 = t.x;
int step0 = t.step;
if(x0==m){
cout<<step0<<endl;
return;
}
for(int i=1;i<=9;i+=2){ //个位只能是奇数
int s=x0/10*10+i;
if(!vis[s] && s!=x0 && isPrime(s)){
vis[s]=1;
node t;
t.x=s;
t.step=step0+1;
q.push(t);
}
}
for(int i=0;i<=9;i++){ //十位
int s=x0/100*100+i*10+x0%10;
if(!vis[s] && s!=x0 && isPrime(s)){
vis[s]=1;
node t;
t.x=s;
t.step=step0+1;
q.push(t);
}
}
for(int i=0;i<=9;i++){ //百位
int s=x0/1000*1000+i*100+x0%100;
if(!vis[s] && s!=x0 && isPrime(s)){
vis[s]=1;
node t;
t.x=s;
t.step=step0+1;
q.push(t);
}
}
for(int i=1;i<=9;i++){ //千位不能为0
int s=i*1000+x0%1000;
if(!vis[s] && s!=x0 && isPrime(s)){
vis[s]=1;
node t;
t.x=s;
t.step=step0+1;
q.push(t);
}
}
}
cout<<"Impossible"<<endl;
return;
}
int main(){
int t; cin>>t;
while(t--){
while(!q.empty()) q.pop();
cin>>n>>m;
memset(vis,0,sizeof(vis));
vis[n]=1; //标记已经用过了
node t;
t.x=n,t.step=0;
q.push(t);
bfs();
}
return 0;
}
原题链接: https://vjudge.net/problem/POJ-3087
题意: 已知两堆牌 s1 和 s2 的初始状态,其牌数均为c,按给定规则能将他们相互交叉组合成一堆牌 s12,再将 s12 的最底下的 c 块牌归为 s1,最顶的 c 块牌归为 s2,依此循环下去。给定输入 s1 和 s2 的初始状态以及预想的最终状态 s12。问 s1 和 s2 经过多少次洗牌之后,最终能达到状态 s12,若永远不可能相同,则输出 -1 。
思路: 退化后的搜索,直接模拟。用 map 把目标状态的实值设为1,把出现过的字符串实值设为 2,洗牌后的字符串如果跟目标字符串相同,则输出洗牌次数。如果不相同,但是该字符串的实值却出现过,说明该状态出现过,也就是说明已经陷入了循环,则输出 -1。
Code(C++):
#include
#include
#include
using namespace std;
int main(){
int t; cin>>t;
for(int k=1;k<=t;k++){
int n; cin>>n;
string s1,s2,s;
cin>>s1>>s2>>s;
map<string,int> ma;
ma[s]=1; //先把字符串s的键值设为1
int ans=0; //洗牌次数
while(1){
string s3=""; //洗牌后的字符串,要初始化为空字符
for(int i=0;i<n;i++) //交织洗牌
s3=s3+s2[i]+s1[i];
ans++; //
if(s==s3){ //如果洗牌后相同则输出
cout<<k<<' '<<ans<<endl;
break;
}
//洗牌后不相同,但是字符串却相同,说明出现过该状态,即进入了循环,也就是找不到了
if(ma[s3]==1){
cout<<k<<' '<<-1<<endl;
break;
}
ma[s3]=1;
for(int i=0;i<n;i++){ //重新分配s1和s2
s1[i]=s3[i];
s2[i]=s3[i+n];
}
}
}
return 0;
}
原题链接: https://vjudge.net/problem/POJ-3414
题意: 有两个水壶,对水壶有三种操作:
FILL(i):将 i 水壶的水填满。
DROP(i):将水壶 i 中的水全部倒掉。
POUR(i, j):将水壶 i 中的水倒到水壶 j 中,若水壶 j 满了,则 i 剩下的就不倒了。
问进行多少步操作,怎么操作可以使得两个水壶中至少有一个的水达到了 C 这个水量。可以的话,输出操作的步骤;不可能则输出impossible。注意初始时两个水壶是空的,没有水。
思路: 两个壶一共有六种操作情况,使用BFS进行搜索,出现过的状态标记起来,具体见代码。
Code(C++):
#include
#include
#include
using namespace std;
int a,b,c;
int ans;
int vis[105][105]; //标记该状态是否出现过
struct node{
int x,y; //代表两个杯子
int step; //操作数
int flag; //标记第几个步骤
node *pre; //前一步操作的路径
};
queue<node> q;
stack<int> s;
void bfs(){
node t;
node left[500]; //瓶子里剩余的水量
t.x=0,t.y=0;
t.flag=0,t.step=0;
t.pre=NULL;
q.push(t);
vis[0][0]=1;
int cnt=0;
while(!q.empty()){
left[++cnt]=q.front();
q.pop();
for(int i=1;i<=6;i++){
switch(i){
case 1: //从水龙头装满第一个水壶
t.x=a,t.y=left[cnt].y;
t.flag=1;
break;
case 2: //从水龙头装满第二个水壶
t.x=left[cnt].x,t.y=b;
t.flag=2;
break;
case 3: //将第一个水壶的水全部倒掉
t.x=0,t.y=left[cnt].y;
t.flag=3;
break;
case 4: //将第二个水壶的水全部倒掉
t.x=left[cnt].x,t.y=0;
t.flag=4;
break;
case 5: //将第一个水壶中的水倒入第二个水壶
if(left[cnt].x>b-left[cnt].y){ //如果第一个水壶所剩水比第二个水壶剩下空间大
t.x=left[cnt].x-(b-left[cnt].y);
t.y=b;
}else{
t.x=0;
t.y=left[cnt].y+left[cnt].x;
}
t.flag=5;
break;
case 6: //将第二个水壶的水倒入第一个水壶
if(left[cnt].y>a-left[cnt].x){ //如果第二个水壶所剩水比第一个水壶剩下空间大
t.x=a;
t.y=left[cnt].y-(a-left[cnt].x);
}else{
t.x=left[cnt].x+left[cnt].y;
t.y=0;
}
t.flag=6;
break;
}
if(vis[t.x][t.y]) continue;
vis[t.x][t.y]=1;
t.step=left[cnt].step+1;
t.pre=&left[cnt];
if(t.x==c || t.y==c){ //一达到指定状态就把所有路径存入栈
ans=t.step;
while(t.pre){
s.push(t.flag);
t=*t.pre;
}
return;
}
q.push(t);
}
}
}
int main(){
cin>>a>>b>>c;
bfs();
if(!ans) cout<<"impossible"<<endl;
else{
cout<<ans<<endl;
while(!s.empty()){
int k=s.top();
s.pop();
switch(k){
case 1: cout<<"FILL(1)"<<endl;break;
case 2: cout<<"FILL(2)"<<endl;break;
case 3: cout<<"DROP(1)"<<endl;break;
case 4: cout<<"DROP(2)"<<endl;break;
case 5: cout<<"POUR(1,2)"<<endl;break;
case 6: cout<<"POUR(2,1)"<<endl;break;
}
}
}
return 0;
}
原题链接: https://vjudge.net/problem/FZU-2150
题意: 给一个 n*m 的地图,每个点有或者无草,可以同时在两个草坪点火,火势只能向上下左右蔓延,蔓延一次时间加1,求全部草烧完的最短燃烧时间。
思路: 用一个结构体数组来存可以燃烧的点,然后两层循环同时暴力遍历这些可以燃烧的点,并且不断更新最短的燃烧的时间。
Code(C++):
#include
#include
#include
using namespace std;
const int INF=0x3f3f3f3f;
int n,m;
int vis[15][15];
char ch[15][15];
int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; //要么不用括号要么用大括号,一定不能用小括号
struct node{
int x,y,step;
}arr[105];
int judge(int x,int y){
if(x>=0&&x<n&&y>=0&&y<m&&!vis[x][y]&&ch[x][y]=='#')
return 1;
return 0;
}
int bfs(node a,node b){
queue<node> q;
q.push(a);
q.push(b);
vis[a.x][a.y]=1;
vis[b.x][b.y]=1;
int cnt=0;
while(!q.empty()){
a=q.front();
cnt=max(cnt,a.step);
for(int i=0;i<4;i++){
b.x=a.x+dir[i][0],b.y=a.y+dir[i][1],b.step=a.step+1;
if(judge(b.x,b.y)){
q.push(b);
vis[b.x][b.y]=1;
}
}
q.pop();
}
return cnt;
}
int main(){
int t; cin>>t;
for(int x=1;x<=t;x++){
cin>>n>>m;
int cnt=0;
for(int i=0;i<n;i++){
cin>>ch[i];
for(int j=0;j<m;j++){
if(ch[i][j]=='#'){
arr[cnt].x=i,arr[cnt].y=j,arr[cnt].step=0;
cnt++;
}
}
}
if(cnt<=2) cout<<"Case "<<x<<": 0"<<endl;
else{
int ans=INF;
for(int i=0;i<cnt;i++){
for(int j=i;j<cnt;j++){
memset(vis,0,sizeof(vis));
int sum=bfs(arr[i],arr[j]);
int flag=0;
for(int k=0;k<n;k++){
for(int l=0;l<m;l++){
if(ch[k][l]=='#'&&!vis[k][l]){
flag=1;
break;
}
}
if(flag) break;
}
if(!flag) ans=min(ans,sum);
}
}
if(ans==INF) cout<<"Case "<<x<<": -1"<<endl;
else cout<<"Case "<<x<<": "<<ans<<endl;
}
}
return 0;
}
原题链接: https://vjudge.net/problem/UVA-11624
题意: 给了很多个火(F)和一个人(J),火和人想四面蔓延的速度都是1,对于 J 来说,要是他走到某点的时间比火蔓延到该点的时间要短,那么他走到该点的时候,火还没蔓延过来,他就可以走到该点,否则,不能进入该点。问人能否走出迷宫?
思路: 两点BFS的题目。先给地图外围加一圈点来判断是否走出迷宫,然后把人的位置和火焰的位置都记录下来,先让火焰入队,最后让人入队(因为先让火不断的烧,看看都可以烧到哪些地方以及相应的所需时间,这样人在逃跑的时候只要在火到达之前赶到那个地方就没事),用两个标记数组来标记火和人是否有走过或者烧过,因为火可以烧人走过的。
Code(C++):
#include
#include
#include
using namespace std;
int n,m,xx,yy;
char ma[1005][1005]; //地图
int vis[1005][1005]; //标记是否被火烧过
int vip[1005][1005]; //标记是否被人走过
int dir[4][2]={1,0,-1,0,0,1,0,-1}; //搜索方向
struct node{
int x,y,step,flag; //flag为0表示人,为1表示火
}a[1005];
int bfs(int num){
node now,next;
queue<node> q;
for(int i=0;i<num;i++){ //火先入队,标记为火
q.push(a[i]);
vis[a[i].x][a[i].y]=1;
}
q.push(a[num]); //人再入队,并标记为人
vip[a[num].x][a[num].y]=1;
while(!q.empty()){
now = q.front();
q.pop();
if(!now.flag && (now.x<1||now.y<1||now.x>n||now.y>m)) return now.step; //走出迷宫时返回步数
for(int i=0;i<4;i++){
next.x=now.x+dir[i][0];
next.y=now.y+dir[i][1];
next.step=now.step+1;
next.flag=now.flag;
//如果是人且没走过,或也没烧过时可以搜下去人的路径
if(!next.flag && !vis[next.x][next.y] && !vip[next.x][next.y] && ma[next.x][next.y]=='.'){
vip[next.x][next.y]=1;
q.push(next);
}
//如果是火且还没烧过并且在范围内可以搜下去火的路径
if(next.flag==1&&!vis[next.x][next.y]&&next.x>=1&&next.y>=1&&next.x<=n&&next.y<=m&&ma[next.x][next.y]=='.'){
vis[next.x][next.y]=1;
q.push(next);
}
}
}
return 0;
}
int main(){
int t; cin>>t;
while(t--){
int num=0; //表示火和人的总数量
memset(vis,0,sizeof(vis));
memset(vip,0,sizeof(vip));
cin>>n>>m;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>ma[i][j];
if(ma[i][j]=='F'){ //找到火焰
a[num].x=i,a[num].y=j;
a[num].flag=1,a[num].step=0;
num++;
}
if(ma[i][j]=='J') //找到人,先暂存,要放在最后面
xx=i,yy=j;
}
}
a[num].x=xx,a[num].y=yy;
a[num].step=0,a[num].flag=0;
for(int i=0;i<=n+1;i++){ //外边围一圈点
ma[i][0]='.';
ma[i][m+1]='.';
}
for(int j=0;j<=m+1;j++){
ma[0][j]='.';
ma[n+1][j]='.';
}
int ans=bfs(num);
if(ans) cout<<ans<<endl;
else cout<<"IMPOSSIBLE"<<endl;
}
return 0;
}
原题链接: https://vjudge.net/problem/POJ-1426
题意: @ 代表油田,* 代表没有油田,如果一个油田8个方向有油田,则它们属于同一块区域,求有多少个区域。
思路: 经典深搜题目,一搜到油田,区域数就加一,同时向八个方向继续搜索,把同一区域的油田标记为不是油田。
注意: 要吸收掉换行符。
Code(C++):
#include
#include
using namespace std;
int n,m;
char map[105][105];
int dir[8][2]={{1,-1},{1,0},{1,1},{0,-1},{0,1},{-1,-1},{-1,0},{-1,1}};
void dfs(int x,int y){
if(map[x][y]=='@') //搜索到的油田标记为不是油田,表示已搜过
map[x][y]='*';
for(int i=0;i<8;i++){ //向八个方向搜索
int xx=x+dir[i][0];
int yy=y+dir[i][1];
if(map[xx][yy]=='@'&&xx>=0&&xx<n&&yy>=0&&yy<m)
dfs(xx,yy);
}
}
int main(){
while(cin>>n>>m && n){
getchar(); //吸掉换行符
for(int i=0;i<n;i++){
for(int j=0;j<m;j++)
cin>>map[i][j];
getchar(); //吸掉换行符
}
int ans=0; //区域的个数
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(map[i][j]=='@'){ //如果是油田就进行深搜与其同一区域的油田
dfs(i,j);
ans++; //同时区域数加1
}
}
}
cout<<ans<<endl;
}
return 0;
}
原题链接: https://vjudge.net/problem/HDU-2612
题意: 给一幅图,有墙,有KFC,有路。两个人要去KFC约会,有很多个KFC,没到达相邻的道路要花费11分钟,问两个人去同一间KFC总共走的最少时间。
思路: 还是两点BFS的题目,不过这道比较简单。在两个人的起始位置开始bfs,也就是进行两次bfs,然后计算到 ‘@’ 总共花费的时间,不断更新最小的时间。
Code(C++):
#include
#include
#include
using namespace std;
int n,m;
char ch[205][205];
int vis[205][205],sum[205][205];
int dir[4][2]={0,1,0,-1,1,0,-1,0};
struct node{
int x,y,step;
};
void bfs(int i,int j){
node a,b;
queue<node> q;
a.x=i,a.y=j,a.step=0;
q.push(a);
while(!q.empty()){
a=q.front();
q.pop();
b.step=a.step+1;
for(int i=0;i<4;i++){
b.x=a.x+dir[i][0];
b.y=a.y+dir[i][1];
if(ch[b.x][b.y]!='#' && b.x>=0 && b.x<n && b.y>=0 && b.y<m && !vis[b.x][b.y]){
vis[b.x][b.y]=1;
sum[b.x][b.y]+=b.step; //记录每个点两个人所走的次数和
q.push(b);
}
}
}
}
int main(){
while(cin>>n>>m){
memset(sum,0,sizeof(sum));
for(int i=0;i<n;i++)
cin>>ch[i];
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(ch[i][j]=='Y' || ch[i][j]=='M'){
memset(vis,0,sizeof(vis)); //两个点,所以在这里标记
bfs(i,j);
}
}
}
int ans=10000000;
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
if(ch[i][j]=='@' && sum[i][j]<=ans && sum[i][j]!=0)
ans=sum[i][j];
}
}
cout<<ans*11<<endl; //每走一次花费11分钟
}
return 0;
}