布线问题

问题描述:印刷电路板将布线区域划分成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
*/

  

布线问题&魔法花园_最短路径的更多相关文章

  1. B20J_2836_魔法树_树链剖分+线段树

    B20J_2836_魔法树_树链剖分+线段树 题意: 果树共有N个节点,其中节点0是根节点,每个节点u的父亲记为fa[u].初始时,这个果树的每个节点上都没有果子(即0个果子). Add u v d ...

  2. 『算法设计_伪代码』贪心算法_最短路径Dijkstra算法

    Dijkstra算法实际上是一个贪婪算法(Greedy algorithm).因为该算法总是试图优先访问每一步循环中距离起始点最近的下一个结点.Dijkstra算法的过程如下图所示. 初始化 给定图中 ...

  3. Dijkstra算法_最短路径_L2-001. 紧急救援

    作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图.在地图上显示有多个分散的城市和一些连接城市的快速道路.每个城市的救援队数量和每一条连接两个城市的快速道路长度都标在地图上.当其他城市有紧急求 ...

  4. Python笔记(二十八)_魔法方法_迭代器

    迭代器用于遍历容器中的数据,但它不是容器,它是一个实现了__next__方法的对象 与迭代器相关的内置函数: iter(): 将一个对象转换成一个迭代器 next(): 访问迭代器中的下一个变量,直到 ...

  5. Python笔记(二十六)_魔法方法_属性的魔法方法

    属性的魔法方法 __getattribute__(self,name):当该类的属性被访问时,自动触发,是最先被触发的属性方法 __setattr__(self,name,value):当一个属性被设 ...

  6. Python笔记(二十三)_魔法方法_字符串的魔法方法

    __str__和__repr__ 如果要把一个类的实例变成字符串,就需要实现魔法方法__str__()和__repr__ >>>class A: def name(self): re ...

  7. Python笔记(二十七)_魔法方法_容器

    定制容器 容器类型的协议: 定制不可变容器,只需要定义__len__()和__getitem__()方法 定制可变容器,需要定义__len__().__getitem__().__setitem__( ...

  8. Python笔记(二十五)_魔法方法_描述符

    描述符的属性方法 __get__(self, instance, owner): 用于访问属性,返回属性的值 __set__(self, instance, value): 用于给属性赋值时,返回属性 ...

  9. Python笔记(二十四)_魔法方法_运算符的魔法方法

    算数运算方法 .反运算方法 以对象A+对象B为例,都是将A作为self值,而B作为other值传入__add__(self,other)方法: 当用户输入A+B,就会调用重写的add方法: >& ...

随机推荐

  1. i.MX RT1010之FlexIO模拟SSI外设

    恩智浦的i.MX RT1010是跨界处理器产品,作为i.MX RT跨界MCU系列的一个新的切入点,i.MX RT1010是成本最低的LQFP封装方式与i.MX RT系列产品一贯的高性能和易用性的结合产 ...

  2. 刷题5. Longest Palindromic Substring

    一.题目说明 Longest Palindromic Substring,求字符串中的最长的回文. Difficuty是Medium 二.我的实现 经过前面4个题目,我对边界考虑越来越"完善 ...

  3. Codeforces Gym 102361A Angle Beats CCPC2019秦皇岛A题 题解

    题目链接:https://codeforces.com/gym/102361/problem/A 题意:给定二维平面上的\(n\)个点,\(q\)次询问,每次加入一个点,询问平面上有几个包含该点的直角 ...

  4. 1010 Radix (25分)

    改了一天也没明白,第7个数据是怎么卡的 #include <bits/stdc++.h> using namespace std; const int maxn=1005; typedef ...

  5. Vue基础笔记3

    插槽指令 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <titl ...

  6. IIS-反向代理配置&&插件安装

    参考:https://www.cnblogs.com/pengcc/p/4329207.html 网络上好多开场的文章就说了好多的原理之类的这里我们直接开始配置.不过也要简单说下win下配置反向代理只 ...

  7. Python学习第二十八课——Django(templates)

    templates 讲后台得到的数据渲染到页面上:话不多说,先看具体代码. urls: from django.conf.urls import url from django.contrib imp ...

  8. Oracle 分析函数 over

    最近在做一个OA系统的统计模块,里面有个功能需要统计出每天新增的用户和累计新增的用户, 只有一张 用户登录的表(用户登录时间,用户ID,等等),效果图: 分析:1,同一用户在一天之内可以登录多次,在这 ...

  9. 【C语言】判断某一正整数是否为完数

    什么是完数? 如果一个数等于它的因子之和,则称该数为“完数”(或“完全数”). 例如,6的因子为1.2.3,而 6=1+2+3,因此6是“完数”. 程序框图:m  问题分析 根据完数的定义,解决本题的 ...

  10. iOS 开发之基于JWT的Token认证机制及解析

    在移动端和服务端通信中,一般有两种认证方式:token 和 session. 1.session/cookie 认证机制: 在服务端创建一个Session对象,同时在客户端的浏览器端创建一个Cooki ...