欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

局部搜索法求解K图染色问题(java版)

程序员文章站 2022-04-15 18:57:34
局部搜索法:K图着色问题问题描述问题分析:伪代码:简单实例图节点文本文件具体实现问题描述对于文件给出的一个有 500 个节点的图形(n500),利用局部搜索算法,求最少可用几种颜色能对其进行着色?并给出对应的着色方案。问题分析:题目的目标是用3种颜色,将图1中的每个节点上色,且保证相邻节点间颜色不同;a)首先我们可以建立三个颜色集合C1、C2、C3,依次将图1中的每个节点随机放入一个颜色集合中;b)计算每个颜色集合中,产生冲突的个数之和作为初始的冲突值initConflicts;c)然...

问题描述

对于文件给出的一个有 500 个节点的图形(n500),利用局部搜索算法,求最
少可用几种颜色能对其进行着色?并给出对应的着色方案。

问题分析:

题目的目标是用尽可能少的颜色,将500节点着色,且保证相邻节点间颜色不同;
a) 首先我们可以建立三个颜色集合C1、C2、C3,依次将图1中的每个节点随机放入一个颜色集合中;
b) 计算每个颜色集合中,产生冲突的个数之和作为初始的冲突值initConflicts;
c) 然后根据C1、C2、C3中的冲突节点对应地分别构建初始的冲突节点集合V1、V2、V3
d) 将Vi(i=1,2,3)中产生冲突的节点移动到其他颜色结合中,得到一个领域;
e) 遍历领域中的每一个解,计算conflicts,选取冲突值最小的解;
f) 若conflits大于0,执行步骤b);否则,输出此时的颜色集合

伪代码:

i n p u t : g [ 500 ] [ 500 ] ← N o d e S e t , K = 4 input:g[500][500]←Node Set,K=4 inputg[500][500]NodeSet,K=4
o u t p u t : C o l o r S e t [ 4 ] output:ColorSet[4] output:ColorSet[4]
b e s t C o l o r S e t ← I n i t C o l o r S e t bestColorSet←InitColorSet bestColorSetInitColorSet
b e s t C o n f l i c t s ← I n i t C o n f l i c t s bestConflicts←InitConflicts bestConflictsInitConflicts
c u r r e n t C o n f l i c t s S e t ← I n i t C o n f l i c t s S e t currentConflictsSet←InitConflictsSet currentConflictsSetInitConflictsSet
d o do do
p r o d u c e produce produce t h e the the l o c a l local local s o l u t i o n solution solution b a s e d based based o n on on b e s t C o l o r s e t bestColorset bestColorset
f o r e a c h foreach foreach s o l u t i o n solution solution i n in in N N N
c u r r e n t C o n f l i c t s ← c h o o s e currentConflicts←choose currentConflictschoose t h e the the m i n i m u m minimum minimum o f of of t h e the the c o n f l i c t s conflicts conflicts o f of of s o l u t i o n solution solution
i f if if c u r r e n t C o n f l i c t s < b e s t C o n f l i c t s currentConflicts<bestConflicts currentConflicts<bestConflicts
b e s t C o l o r s e t ← s o l u t i o n bestColorset←solution bestColorsetsolution
c u r r e n t C o n f l i c t s S e t ← p r o d u c e currentConflictsSet←produce currentConflictsSetproduce t h e the the c o n f l i c t s S e t conflictsSet conflictsSet b a s e d based based o n on on s o l u t i o n solution solution
w h i l e while while b e s t C o n f l i c t s > 0 bestConflicts>0 bestConflicts>0

简单实例

给定如下一个初始的图节点3着色问题,有初始着色方案如图1所示:
局部搜索法求解K图染色问题(java版)
我们可以计算此时的冲突总数为 c o n f l i c t s = 2 + 1 + 1 = 4 conflicts=2+1+1=4 conflicts=2+1+1=4,即冲突对 ( 1 , 3 ) , ( 1 , 4 ) , ( 7 , 8 ) , ( 5 , 6 ) (1,3),(1,4),(7,8),(5,6) (1,3),(1,4),(7,8),(5,6).
我们得到冲突节点集合 c o n f l i c t S e t = { 1 , 3 , 4 , 5 , 6 , 7 , 8 } conflictSet=\{1,3,4,5,6,7,8\} conflictSet={1,3,4,5,6,7,8}.
若我们将节点1的颜色由蓝色变为绿色,如图2所示:
局部搜索法求解K图染色问题(java版)
我们可以计算此时的冲突总数为 c o n f l i c t s = 0 + 1 + 1 = 2 conflicts=0+1+1=2 conflicts=0+1+1=2,即冲突对 ( 7 , 8 ) , ( 5 , 6 ) (7,8),(5,6) (7,8),(5,6).
更新冲突节点集合 c o n f l i c t S e t = { 5 , 6 , 7 , 8 } conflictSet=\{5,6,7,8\} conflictSet={5,6,7,8}.
依次类推,不断地改变冲突节点的颜色,直到总的冲突值为0为止。

局限性

局部搜索算法做每一次更新时,会寻找一个局部最优解,因此算法的收敛速度快,时间复杂度低;但对初始值的选择非常敏感,若初始值选择不合理,很容易陷入局部最优解,无法获得全局最优解。本文用局部搜索算法求解500个节点的图着色问题,求得最少需要4种颜色,只是一个局部最优解;
要求得全局最优解可以使用模拟退火算法,详细内容请参考:
模拟退火算法求解K图着色问题(java版)
实例:
局部搜索法求解K图染色问题(java版)
如图所示:
a)若从起始点1开始局部搜索,只能得到局部最优解
b)若从起始点2开始局部搜索,可以得到局部最优解

图节点文本文件

K图着色500个节点文件
提取码:o177

具体实现

1.先定义一个存储节点的颜色集合类

package package_java;
import java.util.ArrayList;
public class ColorSet{
	public  ArrayList node;
	public ColorSet(){
		node = new ArrayList();
	}
	public void add(int newNode){
		node.add(newNode);
	}
	
	public void set(int index, int newNode){
		node.set(index,newNode);
	}
	
	public  int get(int index){
		return (int)(node.get(index));
	}
	
	public int remove(int index){
		return (int)(node.remove(index));
	}
	
	public boolean remove(Object o){
		return node.remove(o);
	}
	public int indexOf(int oldNode){
		return node.indexOf(oldNode);
	}
	public int length(){
		return node.size();
	}
}
  1. 主类
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.BufferedReader;
import java.util.ArrayList;
import package_java.ColorSet;
import java.util.Random;
public class KGraphColorLocalSearch{
	//	节点数量,颜色数量
	final static int num=500, K=4;
	//	初始化最佳冲突值
	static int bestConflicts=0;
	public static void main(String[] args){
	//	存储节点邻接矩阵
	int[][] g=new int[num][num];
	//	节点文件路径
	String path="D:\\YSA\\Algorithm\\n500.txt";
	//	读取节点文件
	if(!readNodeFile(g,path)){
		System.out.println("fail to read node file !");
	}
	else{
			//	初始化颜色集合,冲突节点集合
			ArrayList<ColorSet> colorList=InitColorSet(num,K);
			ArrayList<ColorSet> conflictsNodeSet=calculateConflicts(g,K,colorList);
			//	输出初始颜色节点集合
			//printNodeSet(K,colorList);
			int steps=0;
			while(bestConflicts>0){
				//	计算最佳的移动节点
				int minDelta=0,src=0,dest=0,moveNode=0;
				for(int i=0;i<K;++i){
					for(int k=0;k<K;++k){
						if(i==k){
							continue;
						}
						ColorSet conflictsNode=conflictsNodeSet.get(i);
						for(int j=0;j<conflictsNode.length();++j){
							int node=conflictsNode.get(j);
							//	计算从颜色i集合将节点node移动到颜色k集合后的冲突差
							int d=calculateOneMoveDeltaConflicts(g,i,k,node,colorList);
							if(d<minDelta){
								src=i;
								dest=k;
								moveNode=node;
								minDelta=d;
							}
						}
					}
					
				}
				// 冲突差值不小于0,说明已得到局部最优解
				if(minDelta==0){
					break;
				}
				// 更新冲突节点集合
				updateConflictsNodeSet(src,dest,moveNode,g,colorList,conflictsNodeSet);
				// 将moveNode从颜色src集合移动到dest集合
				moveNode(src,dest,moveNode,colorList);
				// 更新最佳冲突值,注意minDelta为负数
				bestConflicts +=minDelta;
				System.out.println("第"+(++steps)+"轮:");
				System.out.println("the best conflicts:"+bestConflicts);
				
				/*
				System.out.println(src);
				System.out.println(dest);
				System.out.println(moveNode);
				System.out.println(minDelta);
				printNodeSet(K,conflictsNodeSet);
				*/
			}
			System.out.println("the min conflicts:"+bestConflicts);
			printNodeSet(K,colorList);
				
		}
		
	}
	//	读取节点文件方法
	public static boolean readNodeFile(int[][] g, String path){
		File file=new File(path);
		if(!file.exists()){
			return false;
		}
		ArrayList<String> stringList=new ArrayList<String>();
		try{
			FileReader fr=new FileReader(file);
			BufferedReader br=new BufferedReader(fr);
			String str;
			
			while((str=br.readLine())!=null){
				stringList.add(str);
			}
			br.close();
			fr.close();
		}catch(IOException e){
			e.printStackTrace();
		}
		int m=0,n;
		for(int i=1;i<stringList.size();++i){
			String[] data=stringList.get(i).split("[ ]");
			for(int j=1;j<data.length;++j){
				n=Integer.valueOf(data[j]);
				g[m][n]=1;
			}
			++m;
		}
		return true;
	}
	public static ArrayList<ColorSet> InitColorSet(int n,int K){
		Random rand=new Random();
		rand.setSeed(2004);
		ArrayList<ColorSet> colorList=new ArrayList<ColorSet>(K);
		for(int i=0;i<K;++i){
			ColorSet color=new ColorSet();
			colorList.add(color);
		}
		for(int i=0;i<n;++i){
			int k=rand.nextInt(100)%K;
			ColorSet color=colorList.get(k);
			color.add(i);
		}
		return colorList;
	}
	//	计算从颜色s'r'c集合将节点node移动到颜色的dest集合后的冲突之差
	public static int calculateOneMoveDeltaConflicts(int[][] g, int src,int dest, int node, ArrayList<ColorSet> colorList){
		//	计算节点node在颜色src集合中的冲突数
		ColorSet color= colorList.get(src);
		int inc=0, dec=0;
		for(int i=0;i<color.length();++i){
			if(g[node][color.get(i)]==1){
				++dec;
			}
		}
		//	计算节点node在颜色dest集合中的冲突数
		color= colorList.get(dest);
		for(int i=0;i<color.length();++i){
			if(g[node][color.get(i)]==1){
				++inc;
			}
		}
		return inc-dec;
	}
	//	将moveNode从颜色src集合移动到dest集合
	public static void moveNode(int src,int dest, int node, ArrayList<ColorSet> colorList){
		ColorSet color=colorList.get(src);
		color.remove(color.indexOf(node));
		color=colorList.get(dest);
		color.add(node);
	}
	//	计算总冲突值,生成冲突节点集合
	public static ArrayList<ColorSet> calculateConflicts(int[][] g, int K, ArrayList<ColorSet> colorList ){
		ArrayList<ColorSet> conflictsNodeSet= new ArrayList<ColorSet>(K);
		for(int i=0;i<K;++i){
			ColorSet color=new ColorSet();
			conflictsNodeSet.add(color);
		}
		for(int i=0;i<K;++i){
			ColorSet color=colorList.get(i);
			ColorSet conflictNode=conflictsNodeSet.get(i);
			int conflicts=0;
			for(int j=0;j<color.length()-1;++j){
				int flag=0;
				int row=color.get(j);
				for(int k=j+1;k<color.length();++k){
					int col=color.get(k);
					if(g[row][col]==1){
						if(flag==0){
							conflictNode.add(row);
							flag=1;
						}
						conflictNode.add(col);
						conflicts +=1;	
					}
				}
			}
			bestConflicts +=conflicts;
		}
		return conflictsNodeSet;
	}
	//	更新冲突节点集合
	public static void updateConflictsNodeSet(int src, int dest, int node,int[][] g,ArrayList<ColorSet> colorList, ArrayList<ColorSet> conflictsNodeSet){
		ColorSet conflictsNode=conflictsNodeSet.get(src);
		ColorSet color=colorList.get(src);
		//	移除冲突节点集合中与node冲突的节点,注意若node=41,我们认为与41相邻且大于41的节点算41的出度;只去除出度节点
		for(int i=0;i<color.length();++i){
			int value=color.get(i);
			if(value>node && g[node][value]==1){
				conflictsNode.remove(conflictsNode.indexOf(value));
			}
		}
		//  移除冲突节点集合中node,注意可能存在多个node
		int index;
		while((index=conflictsNode.indexOf(node))!=-1){
			conflictsNode.remove(index);
		}
		conflictsNode=conflictsNodeSet.get(dest);
		color=colorList.get(dest);
		// 向冲突节点中添加node移到dest中后,所产生的冲突节点
		int flag=0;
		for(int i=0;i<color.length();++i){
			int value =color.get(i);
			if(g[node][value]==1){
				if(flag==0){
					conflictsNode.add(node);
					flag=1;
				}
				conflictsNode.add(value);
			}
		}		
	}
	//	输出节点集和
	public static void printNodeSet(int K,ArrayList<ColorSet> nodeList){
		for(int i=0;i<K;++i){
			ColorSet nodeSet=nodeList.get(i);
			int num=nodeSet.length();
			for(int j=0;j<num;++j){
				System.out.print((nodeSet.get(j)+1)+",");
			}
			System.out.println();
			System.out.println();
		}	
	}
}

本文地址:https://blog.csdn.net/shiaiao/article/details/110247210