布线问题&魔法花园_最短路径
布线问题
问题描述:印刷电路板将布线区域划分成n×m个方格阵列,精确的电路布线问题要求确定连接方格a到方格b的最短布线方案;布线时,电路只能沿着直线或直角(方格)布线;已经布线的方格被锁定,即不允许其它线路穿过。
问题分析:从起始位置a开始将它作为第一个扩展结点,与该结点相邻并且可到达的方格成为可行结点被加入到活结点队列中,并且将这些方格标记为1,即从起始方格a到这些方格的距离为1。接着从活结点队列中取出队首结点作为下一个扩展结点,并将当与此时扩展结点相邻且未标记过的方格记为2,并存入活结点队列中。这个过程一直持续到算法搜索到目标方格b或活结点队列为空。
package magicGarden; import java.util.LinkedList;
import java.util.Scanner; /**
* 布线问题
* @author Lican
*
*/
public class WireRouter {
public int[][] grid;//方格阵列;=0表示该方格允许布线;=1表示被封锁,不允许布线
public int size;//方格阵列大小
public int pathLen;//最短线路长度
public LinkedList<Position> q;//扩展结点队列,用list存储
public Position start;//起始位置
public Position finish;//终点
public Position[] path;//最短路径
public WireRouter(int[][] grid,int size,Position start,Position finish){
this.grid=grid;
this.size=size;
this.start=start;
this.finish=finish;
}
/**
* 方格所在位置
* @author Lican
*
*/
public static class Position{
public int row;//行
public int col;//列 public Position(int r ,int c){
row=r;
col=c;
}
}
/**
*计算从起始位置start到目标位置finish的最短布线路径
* @return 找到最短布线路径则返回true,否则返回false
*/
public boolean findPath(){
if(start.row==finish.row&&start.col==finish.col){//start==finish,最短路径为0
pathLen=0;
return true;
} //初始化相对位移
Position[] offset=new Position[4];
offset[0]=new Position(0,1);//右
offset[1]=new Position(1,0);//下
offset[2]=new Position(0,-1);//左
offset[3]=new Position(-1,0);//上 //设置方格阵列“围墙”,方便处理方格边界的情况
for(int i=0;i<=size+1;i++){
grid[0][i]=grid[size+1][i]=1;//顶部和底部
grid[i][0]=grid[i][size+1]=1;//左边和右边
} Position here=new Position(start.row,start.col);
grid[start.row][start.col]=2;//数字0,1表示方格的开放或封锁所以,表示距离时,让所有距离都加2;起始位置的距离为0+2=2
int numOfNbrs=4;//相邻方格数 //以下为标记可达的方格位置
q=new LinkedList<Position>();
Position nbr=new Position(0,0);
do{
//标记可达的相邻方格(每个方格有四个相邻方格)
for(int i=0;i<numOfNbrs;i++){
nbr.row=here.row+offset[i].row;
nbr.col=here.col+offset[i].col;
if(grid[nbr.row][nbr.col]==0){//该方格未被标记,且该方格允许布线
grid[nbr.row][nbr.col]=grid[here.row][here.col]+1;
if(nbr.row==finish.row&&nbr.col==finish.col)
break;
q.add(new Position(nbr.row,nbr.col));
}
} //检测是否到达目标位置finish
if(nbr.row==finish.row&&nbr.col==finish.col)
break;
if(q.isEmpty())
return false; here=q.poll();
}while(true); //构造最短布线路径
pathLen=grid[finish.row][finish.col]-2;
path=new Position[pathLen]; //从目标位置finish开始向起始位置回溯
here=finish;
for(int j=pathLen-1;j>=0;j--){
path[j]=here;
//找前驱位置
for(int i=0;i<numOfNbrs;i++){
nbr.row=here.row+offset[i].row;
nbr.col=here.col+offset[i].col;
if(grid[nbr.row][nbr.col]==j+2)
break;
}
here=new Position(nbr.row,nbr.col);
}
System.out.println("最短路线为:");
for(int j=0;j<pathLen-1;j++){
System.out.println("点"+(j+1)+"位置: 行-"+path[j].row+" 列-"+path[j].col);
}
System.out.println("布线长度为:"+pathLen);
return true;
} public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
System.out.println("请输入方格阵列大小:");
String s1=sc.nextLine();
Integer size=Integer.parseInt(s1); System.out.println("请输入起始点的行和列,用空格隔开:");
String s2=sc.nextLine();
String[] s3=s2.split(" ");
int startRow=Integer.parseInt(s3[0]);
int startCol=Integer.parseInt(s3[1]);
Position start=new Position(startRow,startCol); System.out.println("请输入结束点的行和列,用空格隔开:");
String s4=sc.nextLine();
String[] s5=s4.split(" ");
int finishRow=Integer.parseInt(s5[0]);
int finishCol=Integer.parseInt(s5[1]);
Position finish=new Position(finishRow,finishCol); int[][] grid=new int[size+2][size+2];
System.out.println("请输入方格阵列:");
for(int i=1;i<=size;i++){
String str=sc.nextLine();
String[] strs=str.split(" ");
for(int j=0;j<strs.length;j++){
grid[i][j+1]=Integer.parseInt(strs[j]);
}
} WireRouter w=new WireRouter(grid,size,start,finish);
w.findPath();
}
}
/**
请输入方格阵列大小:
7
请输入起始点的行和列,用空格隔开:
3 2
请输入结束点的行和列,用空格隔开:
4 6
请输入方格阵列:
0 0 1 0 0 0 0
0 0 1 1 0 0 0
0 0 0 0 1 0 0
0 0 0 1 1 0 0
1 0 0 0 1 0 0
1 1 1 0 0 0 0
1 1 1 0 0 0 0
最短路线为:
点1位置: 行-3 列-3
点2位置: 行-4 列-3
点3位置: 行-5 列-3
点4位置: 行-5 列-4
点5位置: 行-6 列-4
点6位置: 行-6 列-5
点7位置: 行-6 列-6
点8位置: 行-5 列-6
布线长度为:9
**/
魔法花园问题
问题描述:
哈利被困在了一个魔法花园里。魔法花园是一个 N*M 的矩形,在其中有着许多植物,这些植物会在时刻 T 消失,如果 T 是 K的倍数。哈利每单位时间都会选择上、下、左、右四个方向的其中一个进行移动。
实验任务:已知哈利的位置和出口的位置,哈利希望你能告诉他最少需要多少时间能离开魔法花园,如果无法移动或无法找到出口,哈利会使用移形幻影。
数据输入:第一行有一个正整数 T(1<=T<=10),表示样例数。每个样例数据的第一行有三个正整数 N、M 和 K(1<=N,M<=100,2<=K<=10),表示魔法花园是 N 行 M 列的。接下来的 N 行每行有 M 个字符,‘0’代表空的地板,“1”代表障碍,“2”代表哈利的起始位置,“3”代表出口的位置。
数据输出:输出一个数,表示哈利离开魔法花园最少需要的时间,如果无法离开则输出“Mobiliarbus”。
/**
* 版本一
*/
package magicGarden; import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Scanner; /**
* 布线问题
* @author Lican
*
*/
public class WireRouter {
public int[][] grid;//方格阵列;=0表示该方格允许布线;=1表示被封锁,不允许布线
public int size;//方格阵列大小
public int K;//控制植物消失的时间间隔
public int pathLen;//最短线路长度
public int timePassed=0;//从开始走总共经过多久时间
public LinkedList<Position> q;//扩展结点队列,用list存储
public Position start;//起始位置
public Position finish;//终点
public Position[] path;//最短路径
public ArrayList<Position> plant;//植物位置
private static Scanner sc;
public WireRouter(int[][] grid,int size,int k,Position start,Position finish, ArrayList<Position> plant2){
this.grid=grid;
this.size=size;
this.K=k;
this.start=start;
this.finish=finish;
this.plant=plant2;
}
/**
* 方格所在位置
* @author Lican
*
*/
public static class Position{
public int row;//行
public int col;//列
public int n;//树形结构的第几层 public Position(int r ,int c, int n1){
row=r;
col=c;
n=n1;
}
} public void disappear(boolean jud){
if(jud==true){
for(Position i:plant){
if(grid[i.row][i.col]!=1)
continue;
grid[i.row][i.col] = 0;
}
}else if(jud==false){
for(Position i:plant){
if(grid[i.row][i.col]!=0)
continue;
grid[i.row][i.col] = 1;
}
}
} /**
*计算从起始位置start到目标位置finish的最短布线路径
* @return 找到最短布线路径则返回true,否则返回false
*/
public boolean findPath(){
if(start.row==finish.row&&start.col==finish.col){//start==finish,最短路径为0
pathLen=0;
return true;
} //初始化相对位移
Position[] offset=new Position[4];
offset[0]=new Position(0,1,-1);//右
offset[1]=new Position(1,0,-1);//下
offset[2]=new Position(0,-1,-1);//左
offset[3]=new Position(-1,0,-1);//上 //设置方格阵列“围墙”,方便处理方格边界的情况
for(int i=0;i<=size+1;i++){
grid[0][i]=grid[size+1][i]=1;//顶部和底部
grid[i][0]=grid[i][size+1]=1;//左边和右边
} Position here=new Position(start.row,start.col,start.n);
grid[start.row][start.col]=2;//数字0,1表示方格的开放或封锁所以,表示距离时,让所有距离都加2;起始位置的距离为0+2=2
int numOfNbrs=4;//相邻方格数 //以下为标记可达的方格位置
q=new LinkedList<Position>();
Position nbr=new Position(0,0,-1);
boolean isDisappear=false;
do{
//标记可达的相邻方格(每个方格有四个相邻方格)
if(nbr.n%K == 0)
disappear(isDisappear=true);
for(int i=0;i<numOfNbrs;i++){
nbr.row=here.row+offset[i].row;
nbr.col=here.col+offset[i].col;
nbr.n=here.n+1;
if(grid[nbr.row][nbr.col]==0){//该方格未被标记,且该方格允许布线
grid[nbr.row][nbr.col]=grid[here.row][here.col]+1;
if(nbr.row==finish.row&&nbr.col==finish.col)
break;
q.add(new Position(nbr.row,nbr.col,nbr.n));
}
}
if(isDisappear==true)
disappear(isDisappear=false);
//检测是否到达目标位置finish
if(nbr.row==finish.row&&nbr.col==finish.col)
break;
if(q.isEmpty())
return false; here=q.poll();
}while(true); System.out.println("最后植物坐标:");
for(Position i:plant)//调试,输出植物坐标
System.out.println(i.row+" "+i.col); //构造最短布线路径
pathLen=grid[finish.row][finish.col]-2;
path=new Position[pathLen]; //从目标位置finish开始向起始位置回溯
here=finish;
for(int j=pathLen-1;j>=0;j--){
path[j]=here;
//找前驱位置
for(int i=0;i<numOfNbrs;i++){
nbr.row=here.row+offset[i].row;
nbr.col=here.col+offset[i].col;
nbr.n=here.n+offset[i].n;
if(grid[nbr.row][nbr.col]==j+2)
break;
}
here=new Position(nbr.row,nbr.col,nbr.n);
}
System.out.println("最短路线为:");
for(int j=0;j<pathLen-1;j++){
System.out.println("点"+(j+1)+"位置: 行-"+path[j].row+" 列-"+path[j].col);
}
System.out.println("布线长度为:"+pathLen); System.out.println("转变后的地图:");//调试,输出转换后的地图,对比查看经过了哪些植物
for(int i=0;i<size;i++){
for(int j=0;j<size;j++)
System.out.print(grid[i+1][j+1]+" ");
System.out.println();
}
return true;
} public static void main(String[] args) {
sc = new Scanner(System.in);
System.out.println("请输入方格阵列大小:");
String s1=sc.nextLine();
Integer size=Integer.parseInt(s1); System.out.println("请输入K:");
String s6=sc.nextLine();
int K=Integer.parseInt(s6); System.out.println("请输入起始点的行和列,用空格隔开:");
String s2=sc.nextLine();
String[] s3=s2.split(" ");
int startRow=Integer.parseInt(s3[0]);
int startCol=Integer.parseInt(s3[1]);
Position start=new Position(startRow,startCol,0); System.out.println("请输入结束点的行和列,用空格隔开:");
String s4=sc.nextLine();
String[] s5=s4.split(" ");
int finishRow=Integer.parseInt(s5[0]);
int finishCol=Integer.parseInt(s5[1]);
Position finish=new Position(finishRow,finishCol,-1); int[][] grid=new int[size+2][size+2];
ArrayList<Position>plant = new ArrayList<Position>();
System.out.println("请输入方格阵列:");
for(int i=1;i<=size;i++){
String str=sc.nextLine();
String[] strs=str.split(" ");
for(int j=0;j<strs.length;j++){
if(Integer.parseInt(strs[j])==1)
plant.add(new Position(i,j+1,-1));
grid[i][j+1]=Integer.parseInt(strs[j]);
}
}
System.out.println("初始植物坐标:");
for(Position i:plant)//调试,输出植物坐标
System.out.println(i.row+" "+i.col);
WireRouter w=new WireRouter(grid,size,K,start,finish,plant);
w.findPath();
}
}
/**
请输入方格阵列大小:
6
请输入K:
2
请输入起始点的行和列,用空格隔开:
1 4
请输入结束点的行和列,用空格隔开:
6 4
请输入方格阵列:
0 0 0 0 0 0
0 0 0 1 0 0
0 1 0 0 0 0
0 0 0 1 0 0
0 0 0 1 0 0
0 0 1 0 1 0
初始植物坐标:
2 4
3 2
4 4
5 4
6 3
6 5
最后植物坐标:
2 4
3 2
4 4
5 4
6 3
6 5
最短路线为:
点1位置: 行-1 列-5
点2位置: 行-2 列-5
点3位置: 行-3 列-5
点4位置: 行-4 列-5
点5位置: 行-5 列-5
点6位置: 行-6 列-5
布线长度为:7
转变后的地图:
5 4 3 2 3 4
6 5 4 1 4 5
7 6 5 6 5 6
8 7 6 1 6 7
0 8 7 8 7 8
0 0 8 9 8 9
**/
下面的魔法花园问题是在上面布线问题的基础上改进的,其实质或者说所用算法仍是布线问题,利用分支限界法,逐层拓展,直至找到出口为止
改进:
1、在结点中加入n,表示拓展探试的层数,也可以理解为树结构的层数。父节点在拓展四个临近子节点时,子节点在父节点的n上加一即可
n的用途:用于计时。每过一个单位时间,树形结构向外拓展一层,也就相当于最终路径中哈利向前走了一步
2、加入plant数组列表,用于记录各植物的坐标
3、加入disappear函数,用于判定植物是否消失。需注意的是,当植物消失时,如果哈利经过了植物所在地方,那么在消失时间过去之时,这个地方的植物就不能再现了,因为要地图需要记录所有探索路径,以便最后的回溯找到最优路径
调试:
在基本的改进思路理清后,进行代码改写,经再三确认,确定思路以及程序无误,但在测试时却总是无法运行出答案,出现 “发生内部错误 Unmatched braces in the pattern” 错误,并且无法实例化 “q=new LinkedList<Position>();”
最后偶尔忽然明悟:原来为了方便处理边界问题,在声明地图数组时多申请了两行两列用于表示边界;所以在mian函数中记录植物位置的时候,就需要将其位置映射为程序中的row和col!
/**
* 版本2,加上可分别指定行列数,可从文件读入
*/
package magicGarden; import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Scanner; /**
* 布线问题
* @author Lican
*
*/
public class MagicGarden {
public int[][] grid;//方格阵列;=0表示该方格允许布线;=1表示被封锁,不允许布线
public int n,m;//方格阵列大小
public int K;//控制植物消失的时间间隔
public int pathLen;//最短线路长度
public LinkedList<Position> q;//扩展结点队列,用list存储
public Position start;//起始位置
public Position finish;//终点
public Position[] path;//最短路径
public ArrayList<Position> plant;//植物位置
private static Scanner in;
public MagicGarden(int[][] grid,int n,int m,int k,Position start,Position finish, ArrayList<Position> plant2){
this.grid=grid;
this.n=n;
this.m=m;
this.K=k;
this.start=start;
this.finish=finish;
this.plant=plant2;
}
/**
* 方格所在位置
* @author Lican
*
*/
public static class Position{
public int row;//行
public int col;//列
public int n;//树形结构的第几层 public Position(int r ,int c, int n1){
row=r;
col=c;
n=n1;
}
} public void disappear(boolean jud){
if(jud==true){
for(Position i:plant){
if(grid[i.row][i.col]!=1)
continue;
grid[i.row][i.col] = 0;
}
}else if(jud==false){
for(Position i:plant){
if(grid[i.row][i.col]!=0)
continue;
grid[i.row][i.col] = 1;
}
}
} /**
*计算从起始位置start到目标位置finish的最短布线路径
* @return 找到最短布线路径则返回true,否则返回false
*/
public boolean findPath(){
if(start.row==finish.row&&start.col==finish.col){//start==finish,最短路径为0
pathLen=0;
return true;
} //初始化相对位移
Position[] offset=new Position[4];
offset[0]=new Position(0,1,-1);//右
offset[1]=new Position(1,0,-1);//下
offset[2]=new Position(0,-1,-1);//左
offset[3]=new Position(-1,0,-1);//上 //设置方格阵列“围墙”,方便处理方格边界的情况
for(int i=0;i<=n+1;i++){
grid[i][0]=grid[i][m+1]=1;//左边和右边
}
for(int j=0;j<=m+1;j++){
grid[0][j]=grid[n+1][j]=1;//顶部和底部
} Position here=new Position(start.row,start.col,start.n);
grid[start.row][start.col]=4;//数字0,1表示方格的开放或封锁所以,表示距离时,让所有距离都加2;起始位置的距离为0+2=2
int numOfNbrs=4;//相邻方格数 //以下为标记可达的方格位置
q=new LinkedList<Position>();
Position nbr=new Position(0,0,-1);
boolean isDisappear=false;
do{
//标记可达的相邻方格(每个方格有四个相邻方格)
if(nbr.n%K == 0)
disappear(isDisappear=true);
for(int i=0;i<numOfNbrs;i++){
nbr.row=here.row+offset[i].row;
nbr.col=here.col+offset[i].col;
nbr.n=here.n+1;
if(grid[nbr.row][nbr.col]==0 || grid[nbr.row][nbr.col]==3){//该方格未被标记,且该方格允许布线
grid[nbr.row][nbr.col]=grid[here.row][here.col]+1;
if(nbr.row==finish.row&&nbr.col==finish.col)
break;
q.add(new Position(nbr.row,nbr.col,nbr.n));
}
}
if(isDisappear==true)
disappear(isDisappear=false);
//检测是否到达目标位置finish
if(nbr.row==finish.row&&nbr.col==finish.col)
break;
if(q.isEmpty())
return false; here=q.poll();
}while(true); System.out.println("最后植物坐标:");
for(Position i:plant)//调试,输出植物坐标
System.out.println(i.row+" "+i.col); System.out.println("转变后的地图:");//调试,输出转换后的地图,对比查看经过了哪些植物
for(int i=0;i<=n+1;i++){
for(int j=0;j<=m+1;j++)
System.out.print(grid[i][j]+"\t");
System.out.println("\n\n");
} //构造最短布线路径
pathLen=grid[finish.row][finish.col]-4;
path=new Position[pathLen]; //从目标位置finish开始向起始位置回溯
here=finish;
for(int j=pathLen-1;j>=0;j--){
path[j]=here;
//找前驱位置
for(int i=0;i<numOfNbrs;i++){
nbr.row=here.row+offset[i].row;
nbr.col=here.col+offset[i].col;
// System.out.print("nbr.row:"+nbr.row+",");//调试
// System.out.println("nbr.col:"+nbr.col);//调试
nbr.n=here.n+offset[i].n;
if(grid[nbr.row][nbr.col]==j+4)
break;
}
here=new Position(nbr.row,nbr.col,nbr.n);
}
System.out.println("最短路线为:");
for(int j=0;j<pathLen-1;j++){
System.out.println("点"+(j+1)+"位置: 行-"+path[j].row+" 列-"+path[j].col);
}
System.out.println("布线长度为:"+pathLen); return true;
} public static void main(String[] args) {
BufferedReader sc;
in = new Scanner(System.in);
String name = in.next();
try {
sc = new BufferedReader(new FileReader(name));
System.out.println("输入行列k,用空格隔开:");
String s1=sc.readLine();
String[] s6=s1.split(" ");
int n=Integer.parseInt(s6[0]);
int m=Integer.parseInt(s6[1]);
int k=Integer.parseInt(s6[2]); int[][] grid=new int[n+2][m+2];
Position start = null,finish = null;
ArrayList<Position>plant = new ArrayList<Position>();
System.out.println("请输入方格阵列:");
for(int i=1;i<=n;i++){
String str=sc.readLine();
String[] strs=str.split(" ");
for(int j=0;j<strs.length;j++){
if(Integer.parseInt(strs[j])==1)
plant.add(new Position(i,j+1,-1));
else if(Integer.parseInt(strs[j])==2){
int startRow = i;
int startCol = j+1;
start = new Position(startRow,startCol,0);
}else if(Integer.parseInt(strs[j])==3){
int finishRow = i;
int finishCol = j+1;
finish = new Position(finishRow,finishCol,-1);
}
grid[i][j+1]=Integer.parseInt(strs[j]);
}
}
System.out.println("初始植物坐标:");
for(Position i:plant)//调试,输出植物坐标
System.out.println(i.row+" "+i.col);
for(int i=1; i<=n; i++){//调试,输出读入二维数组信息
for(int j=1; j<=m; j++)
System.out.print(grid[i][j]+" ");
System.out.println();
}
System.out.println("Start:"+start.row+" "+start.col);
System.out.println("Finish:"+finish.row+" "+finish.col); MagicGarden w=new MagicGarden(grid,n,m,k,start,finish,plant);
w.findPath();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} }
}
/**
map1.txt
输入行列k,用空格隔开:
请输入方格阵列:
初始植物坐标:
2 4
3 2
4 4
5 4
6 3
6 5
0 0 0 2 0 0
0 0 0 1 0 0
0 1 0 0 0 0
0 0 0 1 0 0
0 0 0 1 0 0
0 0 1 3 1 0
Start:1 4
Finish:6 4
最后植物坐标:
2 4
3 2
4 4
5 4
6 3
6 5
转变后的地图:
1 1 1 1 1 1 1 1 1 7 6 5 4 5 6 1 1 8 7 6 1 6 7 1 1 9 8 7 8 7 8 1 1 10 9 8 1 8 9 1 1 0 10 9 10 9 10 1 1 0 0 10 11 10 11 1 1 1 1 1 1 1 1 1 最短路线为:
点1位置: 行-1 列-5
点2位置: 行-2 列-5
点3位置: 行-3 列-5
点4位置: 行-4 列-5
点5位置: 行-5 列-5
点6位置: 行-6 列-5
布线长度为:7
*/
/**
* 版本3,加上可出不去的情况,即哈利每一步都要有移动,如若第一次无法移动,则可移形幻影随机换位,再次无法移动时就报错无法出去
*/
package magicGarden; import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Scanner; /**
* 布线问题
* @author Lican
*
*/
public class MagicGarden1 {
public int[][] grid;//方格阵列;=0表示该方格允许布线;=1表示被封锁,不允许布线
public int n,m;//方格阵列大小
public int K;//控制植物消失的时间间隔
public int pathLen;//最短线路长度
public int privilegeT=0;//使用特权次数
public LinkedList<Position> q;//扩展结点队列,用list存储
public Position start;//起始位置
public Position finish;//终点
public Position[] path;//最短路径
public ArrayList<Position> plant;//植物位置
private static Scanner in;
public MagicGarden1(int[][] grid,int n,int m,int k,Position start,Position finish, ArrayList<Position> plant2){
this.grid=grid;
this.n=n;
this.m=m;
this.K=k;
this.start=start;
this.finish=finish;
this.plant=plant2;
}
/**
* 方格所在位置
* @author Lican
*
*/
public static class Position{
public int row;//行
public int col;//列
public int n;//树形结构的第几层 public Position(int r ,int c, int n1){
row=r;
col=c;
n=n1;
}
} public void disappear(boolean jud){
if(jud==true){
for(Position i:plant){
if(grid[i.row][i.col]!=1)
continue;
grid[i.row][i.col] = 0;
}
}else if(jud==false){
for(Position i:plant){
if(grid[i.row][i.col]!=0)
continue;
grid[i.row][i.col] = 1;
}
}
} /**
*计算从起始位置start到目标位置finish的最短布线路径
* @return 找到最短布线路径则返回true,否则返回false
*/
public boolean findPath(){
if(start.row==finish.row&&start.col==finish.col){//start==finish,最短路径为0
pathLen=0;
return true;
} //初始化相对位移
Position[] offset=new Position[4];
offset[0]=new Position(0,1,-1);//右
offset[1]=new Position(1,0,-1);//下
offset[2]=new Position(0,-1,-1);//左
offset[3]=new Position(-1,0,-1);//上 //设置方格阵列“围墙”,方便处理方格边界的情况
for(int i=0;i<=n+1;i++){
grid[i][0]=grid[i][m+1]=1;//左边和右边
}
for(int j=0;j<=m+1;j++){
grid[0][j]=grid[n+1][j]=1;//顶部和底部
} Position here=new Position(start.row,start.col,start.n);
grid[start.row][start.col]=4;//数字0,1表示方格的开放或封锁所以,表示距离时,让所有距离都加2;起始位置的距离为0+2=2
int numOfNbrs=4;//相邻方格数 //以下为标记可达的方格位置
q=new LinkedList<Position>();
Position nbr=new Position(0,0,-1); int tmp=0;
do{
tmp=0;
if(privilegeT==2){
System.out.println("Mobiliarbus");
System.exit(-1);
}
for(int i=0;i<numOfNbrs;i++){//四周都有植物
nbr.row=here.row+offset[i].row;
nbr.col=here.col+offset[i].col;
nbr.n=here.n+1;
if(grid[nbr.row][nbr.col]==1){
tmp++;
}
}
System.out.println("tmp:"+tmp);//调试
if(tmp==4){
do{
start.row=here.row=1+(int)(Math.random()*(n-1));
start.col=here.col=1+(int)(Math.random()*(m-1));
}while(grid[here.row][here.col]==1||grid[here.row][here.col]==2||grid[here.row][here.col]==3);
System.out.println("第"+(privilegeT+1)+"次变幻后的起始点:"+start.row+","+start.col);
grid[start.row][start.col]=4;
privilegeT++;
}
}while(tmp==4); boolean isDisappear=false;
do{
//标记可达的相邻方格(每个方格有四个相邻方格)
if(nbr.n%K == 0)
disappear(isDisappear=true);
for(int i=0;i<numOfNbrs;i++){
nbr.row=here.row+offset[i].row;
nbr.col=here.col+offset[i].col;
nbr.n=here.n+1;
if(grid[nbr.row][nbr.col]==0 || grid[nbr.row][nbr.col]==3){//该方格未被标记,且该方格允许布线
grid[nbr.row][nbr.col]=grid[here.row][here.col]+1;
if(nbr.row==finish.row&&nbr.col==finish.col)
break;
q.add(new Position(nbr.row,nbr.col,nbr.n));
}
}
if(isDisappear==true)
disappear(isDisappear=false);
//检测是否到达目标位置finish
if(nbr.row==finish.row&&nbr.col==finish.col)
break;
if(q.isEmpty())
return false; here=q.poll();
}while(true); System.out.println("最后植物坐标:");
for(Position i:plant)//调试,输出植物坐标
System.out.println(i.row+" "+i.col); System.out.println("转变后的地图:");//调试,输出转换后的地图,对比查看经过了哪些植物
for(int i=0;i<=n+1;i++){
for(int j=0;j<=m+1;j++)
System.out.print(grid[i][j]+"\t");
System.out.println("\n\n");
} //构造最短布线路径
pathLen=grid[finish.row][finish.col]-4;
path=new Position[pathLen]; //从目标位置finish开始向起始位置回溯
here=finish;
for(int j=pathLen-1;j>=0;j--){
path[j]=here;
//找前驱位置
for(int i=0;i<numOfNbrs;i++){
nbr.row=here.row+offset[i].row;
nbr.col=here.col+offset[i].col;
// System.out.print("nbr.row:"+nbr.row+",");//调试
// System.out.println("nbr.col:"+nbr.col);//调试
nbr.n=here.n+offset[i].n;
if(grid[nbr.row][nbr.col]==j+4)
break;
}
here=new Position(nbr.row,nbr.col,nbr.n);
}
System.out.println("最短路线为:");
for(int j=0;j<pathLen-1;j++){
System.out.println("点"+(j+1)+"位置: 行-"+path[j].row+" 列-"+path[j].col);
}
System.out.println("布线长度为:"+pathLen); return true;
} public static void main(String[] args) {
BufferedReader sc;
in = new Scanner(System.in);
String name = in.next();
try {
sc = new BufferedReader(new FileReader(name));
System.out.println("输入行列k,用空格隔开:");
String s1=sc.readLine();
String[] s6=s1.split(" ");
int n=Integer.parseInt(s6[0]);
int m=Integer.parseInt(s6[1]);
int k=Integer.parseInt(s6[2]); int[][] grid=new int[n+2][m+2];
Position start = null,finish = null;
ArrayList<Position>plant = new ArrayList<Position>();
System.out.println("请输入方格阵列:");
for(int i=1;i<=n;i++){
String str=sc.readLine();
String[] strs=str.split(" ");
for(int j=0;j<strs.length;j++){
if(Integer.parseInt(strs[j])==1)
plant.add(new Position(i,j+1,-1));
else if(Integer.parseInt(strs[j])==2){
int startRow = i;
int startCol = j+1;
start = new Position(startRow,startCol,0);
}else if(Integer.parseInt(strs[j])==3){
int finishRow = i;
int finishCol = j+1;
finish = new Position(finishRow,finishCol,-1);
}
grid[i][j+1]=Integer.parseInt(strs[j]);
}
}
System.out.println("初始植物坐标:");
for(Position i:plant)//调试,输出植物坐标
System.out.println(i.row+" "+i.col);
for(int i=1; i<=n; i++){//调试,输出读入二维数组信息
for(int j=1; j<=m; j++)
System.out.print(grid[i][j]+" ");
System.out.println();
}
System.out.println("Start:"+start.row+" "+start.col);
System.out.println("Finish:"+finish.row+" "+finish.col); MagicGarden1 w=new MagicGarden1(grid,n,m,k,start,finish,plant);
w.findPath();
} catch (IOException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
} }
}
/**
map2.txt
输入行列k,用空格隔开:
请输入方格阵列:
初始植物坐标:
2 4
3 2
4 4
5 4
6 3
6 5
0 0 0 3 0 0
0 0 0 1 0 0
0 1 0 0 0 0
0 0 0 1 0 0
0 0 0 1 0 0
0 0 1 2 1 0
Start:6 4
Finish:1 4
tmp:4
第1次变幻后的起始点:1,2
tmp:1
最后植物坐标:
2 4
3 2
4 4
5 4
6 3
6 5
转变后的地图:
1 1 1 1 1 1 1 1 1 5 4 5 6 0 0 1 1 0 5 0 1 0 0 1 1 0 1 0 0 0 0 1 1 0 0 0 1 0 0 1 1 0 0 0 1 0 0 1 1 0 0 1 4 1 0 1 1 1 1 1 1 1 1 1 最短路线为:
点1位置: 行-1 列-3
布线长度为:2
*/ /**
map3.txt
输入行列k,用空格隔开:
请输入方格阵列:
初始植物坐标:
1 2
1 6
2 1
2 3
2 5
3 2
3 4
3 6
4 1
4 3
4 5
5 2
5 4
5 6
6 1
6 3
6 5
0 1 0 3 0 1
1 0 1 0 1 0
0 1 0 1 0 1
1 0 1 0 1 0
0 1 0 1 0 1
1 0 1 2 1 0
Start:6 4
Finish:1 4
tmp:4
第1次变幻后的起始点:3,1
tmp:4
第2次变幻后的起始点:3,3
Mobiliarbus
*/
/**
map.txt
6 6 2
0 0 0 0 0 0
0 0 0 1 0 0
0 1 0 0 0 0
0 0 0 1 0 0
0 0 0 1 0 0
0 0 1 0 1 0
*/ /**
map1.txt
6 6 2
0 0 0 2 0 0
0 0 0 1 0 0
0 1 0 0 0 0
0 0 0 1 0 0
0 0 0 1 0 0
0 0 1 3 1 0
*/ /**
map2.txt
6 6 2
0 0 0 3 0 0
0 0 0 1 0 0
0 1 0 0 0 0
0 0 0 1 0 0
0 0 0 1 0 0
0 0 1 2 1 0
*/ /**
map3.txt
6 6 2
0 1 0 3 0 1
1 0 1 0 1 0
0 1 0 1 0 1
1 0 1 0 1 0
0 1 0 1 0 1
1 0 1 2 1 0
*/
布线问题&魔法花园_最短路径的更多相关文章
- B20J_2836_魔法树_树链剖分+线段树
B20J_2836_魔法树_树链剖分+线段树 题意: 果树共有N个节点,其中节点0是根节点,每个节点u的父亲记为fa[u].初始时,这个果树的每个节点上都没有果子(即0个果子). Add u v d ...
- 『算法设计_伪代码』贪心算法_最短路径Dijkstra算法
Dijkstra算法实际上是一个贪婪算法(Greedy algorithm).因为该算法总是试图优先访问每一步循环中距离起始点最近的下一个结点.Dijkstra算法的过程如下图所示. 初始化 给定图中 ...
- Dijkstra算法_最短路径_L2-001. 紧急救援
作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图.在地图上显示有多个分散的城市和一些连接城市的快速道路.每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上.当其他城市有紧急求 ...
- Python笔记(二十八)_魔法方法_迭代器
迭代器用于遍历容器中的数据,但它不是容器,它是一个实现了__next__方法的对象 与迭代器相关的内置函数: iter(): 将一个对象转换成一个迭代器 next(): 访问迭代器中的下一个变量,直到 ...
- Python笔记(二十六)_魔法方法_属性的魔法方法
属性的魔法方法 __getattribute__(self,name):当该类的属性被访问时,自动触发,是最先被触发的属性方法 __setattr__(self,name,value):当一个属性被设 ...
- Python笔记(二十三)_魔法方法_字符串的魔法方法
__str__和__repr__ 如果要把一个类的实例变成字符串,就需要实现魔法方法__str__()和__repr__ >>>class A: def name(self): re ...
- Python笔记(二十七)_魔法方法_容器
定制容器 容器类型的协议: 定制不可变容器,只需要定义__len__()和__getitem__()方法 定制可变容器,需要定义__len__().__getitem__().__setitem__( ...
- Python笔记(二十五)_魔法方法_描述符
描述符的属性方法 __get__(self, instance, owner): 用于访问属性,返回属性的值 __set__(self, instance, value): 用于给属性赋值时,返回属性 ...
- Python笔记(二十四)_魔法方法_运算符的魔法方法
算数运算方法 .反运算方法 以对象A+对象B为例,都是将A作为self值,而B作为other值传入__add__(self,other)方法: 当用户输入A+B,就会调用重写的add方法: >& ...
随机推荐
- SniperOj-compare_flag-Writeup
SniperOj-compare_flag-Writeup 题干如上,只给了一个nc命令,那么连接到服务器如下 有如下的python代码 #!/usr/bin/env python from time ...
- 6_4 破损的键盘(UVa11988)<链表>
你用了一个有点坏掉的键盘打字,该键盘会自动按下”Home”键与“End”键,直到打完整个内容以前,你都没有发现到这个问题.本题给定键盘输出的字串(包含Home与End),请你输出该字串在屏幕显示的内容 ...
- Django--模型管理器
参考https://blog.csdn.net/qq_34788903/article/details/87889451 可参考视频 : https://www.bilibili.com/video ...
- watch监听变化
<template> <div> 父级 <childCom1 @click.native="fn()"></childCom1> { ...
- JavaScript 实现单例模式的两种方式
单例模式: 要求一个类只有一个实例化对象存在 这个实例化对象必须提供一个全局对外访问方式 这个实例化对象应当是私有的,不能被外界直接访问或者更改 方式1 get实现 唯一实例化:判断这个对象是否存在, ...
- 【C语言】字符数组,碎碎念
存储方法: (1)字符数组赋值 ①初始化 ]={"China'} 或 ]="China' 注意:字符串可以不加{},单字符必须加 ]={,,} ②键盘输入 () char a; ...
- SpringCloud或SpringBoot+Mybatis-Plus利用mybatis插件实现数据操作记录及更新对比
引文 本文主要介绍如何使用mybatis插件实现拦截数据库操作并根据不同需求进行数据对比分析,主要适用于系统中需要对数据操作进行记录.在更新数据时准确记录更新字段 核心:mybatis插件(拦截器). ...
- python序列化及其相关模块(json,pickle,shelve,xml)详解
什么是序列化对象? 我们把对象(变量)从内存中编程可存储或传输的过程称之为序列化,在python中称为pickle,其他语言称之为serialization ,marshalling ,flatter ...
- JS-try/catch方法判断字符串是否为json格式
定义: try/catch 语句用于处理代码中可能出现的错误信息,出现异常会导致程序崩溃,而try/catch 则可以保证程序的正常运行. try { //执行代码 不报错则 正常执行 不会进入下面的 ...
- 【Go语言系列】第三方框架和库——GIN:快速入门
要求要安装Gin软件包,需要:1.安装Go(需要1.11+版本)2.设置Go工作区 安装1.下载并安装 gin: $ go get -u github.com/gin-gonic/gin 2.将 gi ...