问题描述:
9个硬币排成3*3的二维距阵,正面为T,反面为H,在一次翻转中,若翻转其中一个硬币,则与之上下左右相邻的硬币也要翻转,对于一个给定的硬币排列,试求出使每个硬币均正面朝上的最小翻转次数。示例:
init 1 2
HHH HHH TTT
TTT --> THT --> TTT
HHH TTT TTT
题目分析:我们可以用0表示H,1表示T,则每个硬币的排列可表示为一个二进制数,如:HHHHHHTTT,表示为000000111,即十进的制的7。而最终状态即为111111111,即511。则题目可以转化为,给定一个数,按题目中的翻转方法,求最终得到511的最小翻转次数。
我们需要建一个包含512个结点的图,运用宽搜的方法获得以结点”511”为根的树,然后求从任意一个结点到结点”511”的最短路径。代码如下:
其中,类AbstractGraph,和类UnweightedGraph请见java之图论
import AbstractGraph;
import UnweightedGraph;
import java.util.*;
public class NineTailModel {
public static void main(String[] args) {
System.out.print("Enter an initial nine coin H's and T's");
Scanner input = new Scanner(System.in);
String s = input.nextLine();
char[] initialNode = s.toCharArray();
NineTailModel model = new NineTailModel();
List<Integer> path = model.getShortestPath(NineTailModel.getIndex(initialNode));
System.out.println("the steps to flip the coins are");
for(int i =0;i<path.size();i++){
NineTailModel.printNode(NineTailModel.getNode(path.get(i).intValue()));
}
}
public final static int NUMBER_OF_NODES = 512;
protected AbstractGraph<Integer>.Tree tree; //以结点"511"为根的树
public NineTailModel(){
List<AbstractGraph.Edge> edges = getEdges();
UnweightedGraph<Integer> graph = new UnweightedGraph<Integer>(edges, NUMBER_OF_NODES);
tree = graph.bfs(511);
}
/*
* 获得图的所有的边
*/
private List<AbstractGraph.Edge> getEdges(){
List<AbstractGraph.Edge> edges = new ArrayList<AbstractGraph.Edge>();
for(int u=0;u<NUMBER_OF_NODES;u++){
for(int k=0;k<9;k++){
char[] node = getNode(u);
if(node[k]=='H'){
int v = getFlippedNode(node,k);
edges.add(new AbstractGraph.Edge(v, u));
}
}
}
return edges;
}
/*
* 对参数node的第position个位置进行翻转,
* 返回翻转之后的结点
*/
public static int getFlippedNode(char[] node,int position){
int row = position/3;
int column = position%3;
flipACell(node,row,column);
flipACell(node,row-1,column);
flipACell(node,row+1,column);
flipACell(node,row,column-1);
flipACell(node,row,column+1);
return getIndex(node);
}
public static void flipACell(char[] node,int row,int column){
if(row>=0 && row<=2 && column>=0 &&column<=2){
if(node[row*3+column]=='H')
node[row*3+column]='T';
else
node[row*3+column]='H';
}
}
/*
* 硬币正反面排列转化为十进制数
*/
public static int getIndex(char[] node){
int result = 0;
for(int i=0;i<9;i++)
if(node[i]=='T')
result = 2*result+1;
else
result = 2*result;
return result;
}
/*
* 十进制数转化为硬币正反面排列
*/
public static char[] getNode(int index){
char[] result = new char[9];
for(int i=0;i<9;i++){
int digit = index%2;
if(digit==0){
result[8-i]='H';
}else{
result[8-i]='T';
}
index = index/2;
}
return result;
}
public List<Integer> getShortestPath(int nodeIndex){
return tree.getPath(nodeIndex);
}
public static void printNode(char[] node){
for(int i=0;i<9;i++){
if(i%3 != 2){
System.out.print(node[i]);
}else
System.out.println(node[i]);
}
System.out.println();
}
}