AAAAA

来源:互联网 发布:软件项目测试总结 编辑:程序博客网 时间:2024/06/04 19:49
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.ListIterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * 
 * @author Simson
 *
 * @description this class refers to a char Point from input.
 * Record F,H,G values used in A* algorithm 
 */
class Point{
char icon;
private int F = 0, G = 0, H = 0;
int row, column;

public Point(){
}

/**

* @param c
* @param r
* @param col
*/
public Point(char c, int r, int col){
icon = c;
row = r;
column = col;
}

public void clear(){
H = 0;
F = 0;
G = 0;
}

public void setH(int h){
H = h;
F = G + H;
}

public void setGAndH(int g, int h){
G = g;
H = h;
F = G + H;
}

public int getF(){
return F;
}

public int getG(){
return G;
}
}


class Column{
public Column(int n){
set = new byte[n];
addup = new int[n];
size = n;
}

public void setToZero(){
for(int i=0; i< size; i++){
set[i] = 0;
}
}

int size;
byte[] set;
int[] addup;
}


/**
 * 
 * @author Simson
 *
 * @description main class
 */
public class Orienteering {
//all list generate by rearrange in the current loop
public static ArrayList<ArrayList<Integer>> alllist = new ArrayList<ArrayList<Integer>>();
//reference Map, to reference the best subproblem of the distance got in the last loop
public static HashMap<String, Integer> refMap = new HashMap<String, Integer>();
//reserve Map, to restore the best subproblem of the distance got in the current loop
public static HashMap<String, Integer> resMap = new HashMap<String ,Integer>();
/**

* @param args
* @throws IOException

* @description executable main method
*/
public static void main(String[] args) throws IOException{
BufferedReader BR = new BufferedReader(new InputStreamReader(System.in));
String line = new String();
int width = 0, height = 0;
String pattern = "^([1-9]|[1-9][0-9]|100) ([1-9]|[1-9][0-9]|100)$";
Pattern ptn;
Matcher m;

Point Start = null, End = null;

//input width and height value
line = BR.readLine();

ptn = Pattern.compile(pattern);
m = ptn.matcher(line);
   if (m.find( )) {
    width = Integer.parseInt(m.group(1));
    height = Integer.parseInt(m.group(2));
   } else {
    System.out.println(-1);
    System.exit(-1);
   }

int ln = 1;
String between = Integer.toString(width - 2);
Point coreMap[][] = new Point[height][width];

//input each line
do{
line = BR.readLine();

if(ln == 1 || ln == height){
pattern = "^#[#]{"+between+"}#$";
} else {
pattern = "^#[.@SG#]{"+between+"}#$";
}

ptn = Pattern.compile(pattern);
m = ptn.matcher(line);
//check input characters, and add into coreMap Matrix
if(m.find()){
for(int i = 0; i< width; i++){
if(line.charAt(i) == '.'){
coreMap[ln-1][i] = new Point('.', ln-1, i);
}else if(line.charAt(i) == '@'){
coreMap[ln-1][i] = new Point('@', ln-1, i);
}else if(line.charAt(i) == '#'){
coreMap[ln-1][i] = new Point('#', ln-1, i);
}else if(line.charAt(i) == 'S'){
Start = new Point('S', ln-1, i);
coreMap[ln-1][i] = Start;
}else if(line.charAt(i) == 'G'){
End = new Point('G', ln-1, i);
coreMap[ln-1][i] = End;
}else {}
}
ln++;
} else {
System.out.println(-1);
System.exit(-1);
}
}while(ln <= height);

long startime=System.currentTimeMillis();
if(Start != null && End != null){
ArrayList<Point> checkPoints = new ArrayList<Point>();
//get @ points from coreMap, put them into list of checkPoint
for(int i = 0; i< height; i++){
for(int j = 0; j< width; j++){
if(coreMap[i][j].icon == '@'){
checkPoints.add(coreMap[i][j]);
}
}
}

//check shortest distance from S point to each @ point
int distMap[][] = new int[checkPoints.size() + 2][checkPoints.size() + 2];
for(int i = 0; i< checkPoints.size(); i++){
int distance = AStarDistance(Start, checkPoints.get(i), coreMap);
if(distance == -1){
System.out.println(-1);
System.exit(-1);
} else {
distMap[0][i+1] = distance;
distMap[i+1][0] = distance;
}
}

//check shortest distance from each @ point to G point
for(int i = 0; i< checkPoints.size(); i++){
clearPointMatrix(coreMap, height, width);
int distance = AStarDistance(checkPoints.get(i), End, coreMap);
if(distance == -1){
System.out.println(-1);
System.exit(-1);
} else {
distMap[i+1][ checkPoints.size()+1] = distance;
distMap[checkPoints.size()+1][i+1] = distance;
}
}

//check shortest distance from each @ point to each @ point
for(int i = 0; i< checkPoints.size(); i++){
for(int j = i+1; j< checkPoints.size(); j++){
clearPointMatrix(coreMap, height, width);
int distance = AStarDistance(checkPoints.get(i), checkPoints.get(j), coreMap);
if(distance == -1){
System.out.println(-1);
System.exit(-1);
} else {
distMap[i+1][j+1] = distance;
distMap[j+1][i+1] = distance;
}
}
}
int  n = checkPoints.size()+1;
    int mmin = 0;
    mmin = DPaddup(distMap, n);
    System.out.println("cost:");
    System.out.println(mmin);
} else {
System.out.println(-1);
System.exit(-1);
}
System.out.println("time:"+(System.currentTimeMillis()-startime)+"ms"); 
}

/**

* @param distMap record distance between S @ G
* @param n distMap.size()-1
* @return shortest distance from S to G pass through all @
*/
public static int DPaddup(int[][] distMap, int n){
ArrayList <Integer> mlist;
for(int i = 0; i< n-1; i++){
ArrayList<Integer> arr = getArray(n-1, i+1);
ArrayList<Integer> num = new ArrayList<Integer>();
for(int j = 0; j< n-1; j++)
if(arr.get(j) == 1)
num.add(j+1);

//for all combination
alllist.clear();
rearrange(arr, num, n-1);
resMap.clear();
for(int j = 0; j< alllist.size(); j++){
mlist = alllist.get(j);
ArrayList<Integer> locallist; 
if(mlist.size() == 1){
//S to all single @
locallist = new ArrayList<Integer>();
locallist.addAll(mlist);
int cost = distMap[0][mlist.get(0)];
locallist.add(mlist.get(0));
resMap.put(locallist.toString(), cost);
}else{
//pass through @s
for(int k = 0; k< mlist.size(); k++){
locallist = new ArrayList<Integer>();
locallist.addAll(mlist);
int targ = locallist.get(k);
int min = 900000;
locallist.remove(k);
if(mlist.size() == n-1){
//to the last @, also consider distance of this last @ to G
for(int g = 0; g< locallist.size(); g++){
locallist.add(locallist.get(g));
int cost = refMap.get(locallist.toString());
if(cost + distMap[locallist.get(g)][targ] + distMap[targ][n] < min){
min = distMap[locallist.get(g)][targ] + distMap[targ][n] + cost;
}
locallist.remove(locallist.size()-1);
}
}else{
//decide the best subproblem
for(int g = 0; g< locallist.size(); g++){
locallist.add(locallist.get(g));
int cost = refMap.get(locallist.toString());
if(cost + distMap[locallist.get(g)][targ] < min){
min = distMap[locallist.get(g)][targ] + cost;
}
locallist.remove(locallist.size()-1);
}
}
mlist.add(targ);
resMap.put(mlist.toString(), min);
mlist.remove(mlist.size()-1);
}
}
}
refMap.clear();
refMap.putAll(resMap);
}

//choose shortest path
ArrayList<Integer> valuse = new ArrayList<Integer>(refMap.values());
int min = 9000;
for(int v = 0; v< valuse.size(); v++)
if(min> valuse.get(v))
min = valuse.get(v);
return min;
}

/**

* @param m 
* @param n
* @return generate init 0-1 list
* for example: getArray(3, 2) will return [1,1,0], getArray(4,3) return [1,1,1,0]
*/
public static ArrayList<Integer> getArray(int m, int n){
ArrayList<Integer> arr = new ArrayList<Integer>();
for(int i = 0; i< m; i++){
arr.add(0);
}
for(int i = 0; i< n; i++){
arr.set(i, 1);
}
return arr;
}


/**

* @param arr  0-1list
* @param num  number list like 123 from 1110,generated from arr 
* @param m length of arr
*/
public static void rearrange(ArrayList<Integer> arr, ArrayList<Integer>num, int m){
ArrayList<Integer> ins = new ArrayList<Integer>();
ins.addAll(arr);
ArrayList<Integer> numins = new ArrayList<Integer>();
numins.addAll(num);
alllist.add(numins);

for(int i = 1; i< m; i++){
if(arr.get(i-1)== 1 && arr.get(i)== 0){
ins = new ArrayList<Integer>();
numins = new ArrayList<Integer>();
arr.set(i-1, 0);
arr.set(i, 1);
num.set(num.indexOf(new Integer(i)), i+1);
numins.addAll(num);
ins.addAll(arr);
rearrange(ins, numins, i);
}
}
return;
}


/**

* @param mat M*N char matrix used to record input.
* @param height M
* @param width N

* @description Running through matrix of Point type, and clear these point's 'F', 'G', 'H' value to zero.
*/
protected static void clearPointMatrix(Point mat[][], int height, int width){
for(int i = 0; i< height; i++)
for(int j= 0; j< width; j++)
mat[i][j].clear();
}

/**

* @param Start 
* @param End
* @return distance between Start and End
*/
protected static int distBetween(Point Start, Point End){
return Math.abs((Start.row - End.row))+ Math.abs((Start.column - End.column));
}

/**

* @param list LinkedList of point type
* @param point 

* @description insert point into list based on value of point.F in ascending order
*/
protected static void sortedAdd(LinkedList<Point> list, Point point){
ListIterator<Point> itr = list.listIterator();
    while (itr.hasNext()) {
            if(point.getF() > itr.next().getF()){
            continue;
            } else {
            itr.previous();
            itr.add(point);
            break;
            }
        }
    if(!itr.hasNext())//if iterator points to the last point
    itr.add(point);
}

/**

* @param map Matrix used to reference point's F, G, H values for A* algorithm.
* @param size Map's size 
* @param Start
* @param End
* @return Distance between two points, if they can not reach each other, return -1

* @description Use A* algorithm to determine the shortest distance from individual S to @, @ to @, and @ to G
*/
protected static int AStarDistance(Point Start, Point End, Point coreMap[][]){
LinkedList<Point> openList = new LinkedList<Point>();
ArrayList<Point> closeList = new ArrayList<Point>();

int iRet = -1;                       
Point current = null;
Point adjacent = null;
openList.add(Start);
Start.setH(distBetween(Start, End));

while(!openList.isEmpty()){
current = openList.get(0);                      //openlist is sorted,so the minimum in openlist is its first item
int offset[] = {0, 1, 1, 0, 0, -1, -1, 0};

for(int i=0; i< 8; i+=2){

adjacent = coreMap[current.row+ offset[i]][current.column + offset[i+1]];
if((adjacent.icon != '#') && (!closeList.contains(adjacent))){
if(!openList.contains(adjacent)){

adjacent.setGAndH(current.getG()+1, distBetween(adjacent, End));
sortedAdd(openList, adjacent);
} else {

if(current.getG() + 1 < adjacent.getG()){
adjacent.setGAndH(current.getG()+1, distBetween(adjacent, End));
}
}
}
}

closeList.add(current);
if(current.row == End.row && current.column == End.column){
break;
}
openList.remove(current);

}

if(openList.isEmpty())                              //if openlist is empty, then there's no path from Start to End
iRet = -1;
else
iRet = closeList.get(closeList.size()-1).getG();//if reach End point,break out while-loop in middle, the newest in closelist is distance

return iRet;
}
}
0 0