Java学习第35天:图的 m 着色问题
问题描述:
给定无向连通图 G 和 m 种不同的颜色。用这些颜色为图 G 和各顶点着色,每个顶点着一种颜色。是否有一种着色法使得图 G 中每条边的两个顶点着不同的颜色。这个问题是图的 m 可着色判定问题。若一个图最少需要 m 种颜色才能使图中的每条边连接的两个顶点着不同的颜色,则称这个数 m 为该图的色数。求一个图的色数 m 的问题称为图的 m 可着色优化问题。
四色问题是m图着色问题的一个特例,根据四色原理,证明平面或球面上的任何地图的所有区域都至多可用四种、颜色来着色,并使任何两个有一段公共边界的相邻区域没有相同的颜色。这个问题可将平面图转换成对平面点的着色判定问题,将地图的每个区域变成一个结点,若两个区域相邻,则相应的结点用一条边连接起来。如将五个区域换成用点的方式表示,如下图:
即用矩阵的表示如下:
用回溯法解空间,先假设三种颜色和三个点,解空间如下:
代码如下:
//图的m着色
/**
* @Description: 着色
* @Param: [paraNumColors]
* @return: void
*/
public void coloring(int paraNumColors) {
//初始化
int tpNumNodes = connectivityMatrix.getColumns();
int[] tpColorScheme = new int[tpNumNodes];
Arrays.fill(tpColorScheme, -1);
coloring(paraNumColors, 0, tpColorScheme);
}
/**
* @Description: 着色。输出所有可能的方式
* @Param: [paraNumColors(颜色数量), paraCurNumNodes, paraCurColoring]
* @return: void
*/
private void coloring(int paraNumColors, int paraCurNumNodes, int[] paraCurColoring) {
int tpNumNodes = connectivityMatrix.getColumns();
System.out.println("coloring: paraNumColors = " + paraNumColors + ", paraCurrentNumNodes = "
+ paraCurNumNodes + ", paraCurrentColoring" + Arrays.toString(paraCurColoring));
//说明已经完成了所有节点的颜色分配
if (paraCurNumNodes >= tpNumNodes) {
System.out.println("Find one:" + Arrays.toString(paraCurColoring));
return;
}
//尝试所有可能的颜色
for (int i = 0; i < paraNumColors; i++) {
paraCurColoring[paraCurNumNodes] = i;
if (!colorConflict(paraCurNumNodes + 1, paraCurColoring)) {
coloring(paraNumColors, paraCurNumNodes + 1, paraCurColoring);
}
}
}
/**
* @Description: 着色是否冲突。只将当前节点与相连接的节点比较
* @Param: [paraCurNumNodes, paraCurColoring]
* @return: boolean
*/
private boolean colorConflict(int paraCurNumNodes, int[] paraCurColoring) {
for (int i = 0; i < paraCurNumNodes - 1; i++) {
//先判断当前节点与哪些节点相连接
if (connectivityMatrix.getValue(paraCurNumNodes - 1, i) == 0) {
continue;
}
//若连接,则判断它们的颜色是否相同
if (paraCurColoring[paraCurNumNodes - 1] == paraCurColoring[i]) {
return true;
}
}
return false;
}
/**
* @Description: 着色测试
* @Param: []
* @return: void
*/
public static void coloringTest() {
int[][] tempMatrix = { { 0, 1, 1, 0 }, { 1, 0, 0, 1 }, { 1, 0, 0, 0 }, { 0, 1, 0, 0 } };
Graph tempGraph = new Graph(tempMatrix);
tempGraph.coloring(3);
}
public static void main(String args[]) {
System.out.println("Hello!");
Graph tempGraph = new Graph(3);
System.out.println(tempGraph);
// Unit test.
getConnectivityTest();
breadthFirstTraversalTest();
depthFirstTraversalTest();
coloringTest();
}// Of main
运行结果:
coloring: paraNumColors = 3, paraCurrentNumNodes = 0, paraCurrentColoring[-1, -1, -1, -1]
coloring: paraNumColors = 3, paraCurrentNumNodes = 1, paraCurrentColoring[0, -1, -1, -1]
coloring: paraNumColors = 3, paraCurrentNumNodes = 2, paraCurrentColoring[0, 1, -1, -1]
coloring: paraNumColors = 3, paraCurrentNumNodes = 3, paraCurrentColoring[0, 1, 1, -1]
coloring: paraNumColors = 3, paraCurrentNumNodes = 4, paraCurrentColoring[0, 1, 1, 0]
Find one:[0, 1, 1, 0]
coloring: paraNumColors = 3, paraCurrentNumNodes = 4, paraCurrentColoring[0, 1, 1, 2]
Find one:[0, 1, 1, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 3, paraCurrentColoring[0, 1, 2, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 4, paraCurrentColoring[0, 1, 2, 0]
Find one:[0, 1, 2, 0]
coloring: paraNumColors = 3, paraCurrentNumNodes = 4, paraCurrentColoring[0, 1, 2, 2]
Find one:[0, 1, 2, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 2, paraCurrentColoring[0, 2, 2, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 3, paraCurrentColoring[0, 2, 1, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 4, paraCurrentColoring[0, 2, 1, 0]
Find one:[0, 2, 1, 0]
coloring: paraNumColors = 3, paraCurrentNumNodes = 4, paraCurrentColoring[0, 2, 1, 1]
Find one:[0, 2, 1, 1]
coloring: paraNumColors = 3, paraCurrentNumNodes = 3, paraCurrentColoring[0, 2, 2, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 4, paraCurrentColoring[0, 2, 2, 0]
Find one:[0, 2, 2, 0]
coloring: paraNumColors = 3, paraCurrentNumNodes = 4, paraCurrentColoring[0, 2, 2, 1]
Find one:[0, 2, 2, 1]
coloring: paraNumColors = 3, paraCurrentNumNodes = 1, paraCurrentColoring[1, 2, 2, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 2, paraCurrentColoring[1, 0, 2, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 3, paraCurrentColoring[1, 0, 0, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 4, paraCurrentColoring[1, 0, 0, 1]
Find one:[1, 0, 0, 1]
coloring: paraNumColors = 3, paraCurrentNumNodes = 4, paraCurrentColoring[1, 0, 0, 2]
Find one:[1, 0, 0, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 3, paraCurrentColoring[1, 0, 2, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 4, paraCurrentColoring[1, 0, 2, 1]
Find one:[1, 0, 2, 1]
coloring: paraNumColors = 3, paraCurrentNumNodes = 4, paraCurrentColoring[1, 0, 2, 2]
Find one:[1, 0, 2, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 2, paraCurrentColoring[1, 2, 2, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 3, paraCurrentColoring[1, 2, 0, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 4, paraCurrentColoring[1, 2, 0, 0]
Find one:[1, 2, 0, 0]
coloring: paraNumColors = 3, paraCurrentNumNodes = 4, paraCurrentColoring[1, 2, 0, 1]
Find one:[1, 2, 0, 1]
coloring: paraNumColors = 3, paraCurrentNumNodes = 3, paraCurrentColoring[1, 2, 2, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 4, paraCurrentColoring[1, 2, 2, 0]
Find one:[1, 2, 2, 0]
coloring: paraNumColors = 3, paraCurrentNumNodes = 4, paraCurrentColoring[1, 2, 2, 1]
Find one:[1, 2, 2, 1]
coloring: paraNumColors = 3, paraCurrentNumNodes = 1, paraCurrentColoring[2, 2, 2, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 2, paraCurrentColoring[2, 0, 2, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 3, paraCurrentColoring[2, 0, 0, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 4, paraCurrentColoring[2, 0, 0, 1]
Find one:[2, 0, 0, 1]
coloring: paraNumColors = 3, paraCurrentNumNodes = 4, paraCurrentColoring[2, 0, 0, 2]
Find one:[2, 0, 0, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 3, paraCurrentColoring[2, 0, 1, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 4, paraCurrentColoring[2, 0, 1, 1]
Find one:[2, 0, 1, 1]
coloring: paraNumColors = 3, paraCurrentNumNodes = 4, paraCurrentColoring[2, 0, 1, 2]
Find one:[2, 0, 1, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 2, paraCurrentColoring[2, 1, 2, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 3, paraCurrentColoring[2, 1, 0, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 4, paraCurrentColoring[2, 1, 0, 0]
Find one:[2, 1, 0, 0]
coloring: paraNumColors = 3, paraCurrentNumNodes = 4, paraCurrentColoring[2, 1, 0, 2]
Find one:[2, 1, 0, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 3, paraCurrentColoring[2, 1, 1, 2]
coloring: paraNumColors = 3, paraCurrentNumNodes = 4, paraCurrentColoring[2, 1, 1, 0]
Find one:[2, 1, 1, 0]
coloring: paraNumColors = 3, paraCurrentNumNodes = 4, paraCurrentColoring[2, 1, 1, 2]
Find one:[2, 1, 1, 2]
Java学习第36天:邻连表
- 相当于图的压缩存储. 每一行数据用一个单链表存储.
- 重写了广度优先遍历和深度优先遍历. 可以发现, 使用队列的机制不变. 仅仅是把其中的 for 循环换成了 while, 避免检查不存在的边. 如果图很稀疏的话, 可以降低时间复杂度.
package day36;
import day13.LinkedList;
import day22.CircleObjectQueue;
import day25.ObjectStack;
public class NeighborList {
class NeighborNode {
//图序号
int data;
//下一节点
NeighborNode next;
public NeighborNode(int data) {
this.data = data;
next = null;
}
}
//节点数量
int numNodes;
//每行的头节点
NeighborNode[] headers;
/**
* @Description: 构造函数
* @Param: [paraMatrix]
* @return:
*/
public NeighborList(int[][] paraMatrix) {
numNodes = paraMatrix.length;
NeighborNode tpNode;
headers = new NeighborNode[numNodes];
//链接上每个节点相邻接的节点
for (int i = 0; i < numNodes; i++) {
headers[i] = new NeighborNode(i);
tpNode = headers[i];
for (int j = 0; j < numNodes; j++) {
if (paraMatrix[i][j] == 0) {
continue;
}
tpNode.next = new NeighborNode(j);
tpNode = tpNode.next;
}
}
}
@Override
public String toString() {
String resString = "NeighborList: \n";
NeighborNode tpNode;
for (int i = 0; i < numNodes; i++) {
tpNode = headers[i];
while (tpNode.next != null) {
resString += tpNode.data + "->";
tpNode = tpNode.next;
}
resString += tpNode.data + "\n";
}
return resString;
}
/**
* @Description: 广度优先遍历
* @Param: [paraStartIndex]
* @return: java.lang.String
*/
public String breadthFirstTraversal(int paraStartIndex) {
CircleObjectQueue tpQueue = new CircleObjectQueue();
String resString = "";
boolean[] tpVisitedArray = new boolean[numNodes];
tpVisitedArray[paraStartIndex] = true;
resString += paraStartIndex;
tpQueue.enqueue(paraStartIndex);
//根据节点去遍历
int tpIndex;
Integer tempInteger = (Integer) tpQueue.dequeue();
NeighborNode tpNode;
while (tempInteger != null) {
tpIndex = tempInteger.intValue();
tpNode = headers[tpIndex];
while (tpNode.next != null) {
tpNode = tpNode.next;
if (tpVisitedArray[tpNode.data]) {
continue;
}
tpQueue.enqueue(tpNode.data);
tpVisitedArray[tpNode.data] = true;
resString += tpNode.data;
}
tempInteger = (Integer) tpQueue.dequeue();
}
return resString;
}
/**
* @Description: 广度优先遍历测试
* @Param: []
* @return: void
*/
public static void breadthFirstTraversalTest() {
// Test an undirected graph.
int[][] tempMatrix = {{0, 1, 1, 0}, {1, 0, 0, 1}, {1, 0, 0, 1}, {0, 1, 1, 0}};
NeighborList tpNeighborList = new NeighborList(tempMatrix);
System.out.println(tpNeighborList);
String tempSequence = "";
try {
tempSequence = tpNeighborList.breadthFirstTraversal(2);
} catch (Exception e) {
System.out.println(e);
}
System.out.println("The breadth first order of visit: " + tempSequence);
}
/**
* @Description: 深度优先遍历
* @Param: [paraStartIndex]
* @return: java.lang.String
*/
public String depthFirstTraversal(int paraStartIndex) {
ObjectStack tpStack = new ObjectStack();
String resString = "";
boolean[] tpVisitedArray = new boolean[numNodes];
tpVisitedArray[paraStartIndex] = true;
NeighborNode tpNode = headers[paraStartIndex];
;
resString += paraStartIndex;
tpStack.push(tpNode);
int num = 1;
while (num < numNodes) {
while (tpNode.next != null && tpVisitedArray[tpNode.next.data]) {
tpNode = tpNode.next;
}
//回溯
if (tpNode.next == null) {
tpNode = (NeighborNode) tpStack.pop();
continue;
}
resString += tpNode.next.data;
tpStack.push(tpNode.next);
tpVisitedArray[tpNode.next.data] = true;
tpNode = headers[tpNode.next.data];
num++;
}
return resString;
}
/**
* @Description: 深度优先遍历测试
* @Param: []
* @return: void
*/
public static void depthFirstTraversalTest() {
// Test an undirected graph.
int[][] tempMatrix = {{0, 1, 1, 0}, {1, 0, 0, 1}, {1, 0, 0, 0}, {0, 1, 0, 0}};
NeighborList tpNeighborList = new NeighborList(tempMatrix);
System.out.println(tpNeighborList);
String tempSequence = "";
try {
tempSequence = tpNeighborList.depthFirstTraversal(0);
} catch (Exception ee) {
System.out.println(ee);
}
System.out.println("The depth first order of visit: " + tempSequence);
}
public static void main(String[] args) {
int[][] tempMatrix = {{0, 1, 0, 0}, {0, 0, 0, 1}, {1, 0, 0, 0}, {0, 1, 1, 0}};
NeighborList tpList = new NeighborList(tempMatrix);
System.out.println(tpList);
breadthFirstTraversalTest();
depthFirstTraversalTest();
}
}
测试有向图:
测试结果:
NeighborList:
0->1
1->3
2->0
3->1->2
NeighborList:
0->1->2
1->0->3
2->0->3
3->1->2
The breadth first order of visit: 2031
NeighborList:
0->1->2
1->0->3
2->0
3->1
The depth first order of visit: 0132