USACO_2_4_Overfencing

本文介绍了一种使用广度优先搜索求解迷宫中最远点距离出口的最大距离的算法。通过不断更新并搜索可达点来优化路径长度,最终得出迷宫中任意点到最近出口的最大距离。
使用广度优先所搜,用distance[i][j]表示点(i,j)到最近出口的距离

对于题目给出的数据,一开始(2,1)(2,4)的distance为1{从(0,0)开始计算},其它点的distance都为一个比较大的值,且把这两个点加入“搜索点集合”中

不断的从“搜索点集合”中“拿出”一个点,当这个点的distance+1小于它旁边的另一个点的distance时,就跟新另一个点的distance,且把另一个点加入“搜索点集合”中。当然,这两个点必须是联通的。

直到集合为空,然后找出最大的distance

下面说明算法时间效率为O(w*h)

注意运行时间与向集合中加入点的次数成线性关系

考虑到只有一个出口时,每一个点的distance值仅会被更新一次,而有两个出口时每一个点的distance值最多被更新两次,所以每个点最多被加入集合两次,效率为O(w*h)



ContractedBlock.gifExpandedBlockStart.gifCode
ExpandedBlockStart.gifContractedBlock.gif/**//*
ID: sdjllyh1
PROG: maze1
LANG: JAVA
complete date: 2008/12/21
complexity: O(w * h)
author: LiuYongHui From GuiZhou University Of China
more article: www.cnblogs.com/sdjls
*/


import java.io.*;
import java.util.*;

public class maze1
ExpandedBlockStart.gifContractedBlock.gif
{
    
private static int w, h;
    
private static int[][] distance;//每个点离最近出口的距离
    private static char[][] map;//迷宫地图
    private static int longestDistance;//输出的答案
    private static LinkedList points = new LinkedList();//广度优先搜索需要搜索的点队列

    
public static void main(String[] args) throws IOException
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        init();
        run();
        output();
        System.exit(
0);
    }


    
private static void run()
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
//当还有需要搜索的点时
        while (!points.isEmpty())
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
//获得当前需要搜索的点
            point p = (point)points.getFirst();
            
//从队列中移除此点
            points.removeFirst();
            
//分别考虑四个方向
            for (int facing = 0; facing < 4; facing++)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
//如果下一步可以走且此点的distance加1小于下一点的distance(发现最优路线)
                if (canMoveAndBester(p, facing))
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    
//获得下一点
                    point nextPoint = move(p, facing);
                    
//跟新下一点的distance
                    distance[nextPoint.x][nextPoint.y] = distance[p.x][p.y] + 1;
                    
//把下一点加入搜索队列
                    points.addLast(nextPoint);
                }

            }

        }

        
//计算最大的distance
        longestDistance = calcLongestDistance();
    }


    
private static int calcLongestDistance()
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
int retDistance = 0;
        
for (int i = 0; i < h; i++)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
for (int j = 0; j < w; j++)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                retDistance 
= Math.max(retDistance, distance[i][j]);
            }

        }

        
return retDistance;
    }

    
//如果下一点能走且从p点(当前点)走到下一点的方案更好时返回true
    private static boolean canMoveAndBester(point p, int facing)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
boolean retCanMove = true;

        
switch (facing)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
case 0:
                
//如果走到边界或此方案不是更好的或有障碍物,下面类似
                if ((p.x == 0|| (distance[p.x - 1][p.y] <= distance[p.x][p.y] + 1|| (map[p.x * 2][p.y * 2 + 1== '-'))
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    retCanMove 
= false;
                }

                
break;
            
case 1:
                
if ((p.y == w - 1|| (distance[p.x][p.y + 1<= distance[p.x][p.y] + 1|| (map[p.x * 2 + 1][(p.y + 1* 2== '|'))
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    retCanMove 
= false;
                }

                
break;
            
case 2:
                
if ((p.x == h - 1|| (distance[p.x + 1][p.y] <= distance[p.x][p.y] + 1|| (map[(p.x + 1* 2][p.y * 2 + 1== '-'))
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    retCanMove 
= false;
                }

                
break;
            
case 3:
                
if ((p.y == 0|| (distance[p.x][p.y - 1<= distance[p.x][p.y] + 1|| (map[p.x * 2 + 1][p.y * 2== '|'))
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    retCanMove 
= false;
                }

                
break;
        }

        
return retCanMove;
    }

    
//获得下一点,facing是方向,0、1、2、3分别表示上、右、下、左
    private static point move(point p, int facing)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        point retPoint 
= null;
        
switch (facing)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
case 0:
                retPoint 
= new point(p.x - 1, p.y);
                
break;
            
case 1:
                retPoint 
= new point(p.x, p.y + 1);
                
break;
            
case 2:
                retPoint 
= new point(p.x + 1, p.y);
                
break;
            
case 3:
                retPoint 
= new point(p.x, p.y - 1);
                
break;
        }

        
return retPoint;
    }


    
private static void init() throws IOException
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        BufferedReader f 
= new BufferedReader(new FileReader("maze1.in"));
        StringTokenizer st 
= new StringTokenizer(f.readLine());
        w 
= Integer.parseInt(st.nextToken());
        h 
= Integer.parseInt(st.nextToken());

        map 
= new char[h*2+1][w * 2 + 1];
        distance 
= new int[h][w];
        
for (int i = 0; i < h; i++)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
for (int j = 0; j < w; j++)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                distance[i][j] 
= Integer.MAX_VALUE;
            }

        }


        
for (int i = 0; i < h * 2 + 1; i++)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            String str 
= f.readLine();
            
for (int j = 0; j < w * 2 + 1; j++)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                map[i][j] 
= str.charAt(j);

                
if ((i == 0&& (map[i][j] == ' '))
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    distance[
0][(j - 1/ 2= 1;
                    points.addLast(
new point(0, (j - 1/ 2));
                }

                
if ((i == h * 2&& (map[i][j] == ' '))
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    distance[h 
- 1][(j - 1/ 2= 1;
                    points.addLast(
new point(h - 1, (j - 1/ 2));
                }

                
if ((j == 0&& (map[i][j] == ' '))
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    distance[(i 
- 1/ 2][0= 1;
                    points.addLast(
new point((i - 1/ 20));
                }

                
if ((j == w * 2&& (map[i][j] == ' '))
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    distance[(i 
- 1/ 2][w - 1= 1;
                    points.addLast(
new point((i - 1/ 2, w - 1));
                }

            }

        }

        f.close();
    }


    
private static void output() throws IOException
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        PrintWriter out 
= new PrintWriter(new BufferedWriter(new FileWriter("maze1.out")));
        out.println(longestDistance);
        out.close();
    }

}


class point
ExpandedBlockStart.gifContractedBlock.gif
{
    
public int x;
    
public int y;
    
public point(int x, int y)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
this.x = x;
        
this.y = y;
    }

}

转载于:https://www.cnblogs.com/SDJL/archive/2008/12/21/1359328.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值