利用虚拟二维数组求染色问题

在校园招聘季节里,已知有n位学生,他们分别对m个研究组中的若干个感兴趣。为了满足所有的学生需求,如果每个见面会的时间是t,如何安排才能使得所有见面会总时间最短?

这是来自《编程之美》的第57页的一道题,具体的做法如下:

1.A同学对1,2,3小组感兴趣,写成A(1,2,3) B同学对1,3,4小组感兴趣,写成B(1,3,4)  转化为图如下:

 

2.这个问题转化为给图染色,有边的两节点染色要不一致,最少使用多少种颜色

3.针对这个问题,《编程之美》给出了两种解法,一种解法时间复杂度较大,另一种较小,但是都没有给出详细的代码,只给了思路(估计代码比较冗长吧),现在的话呢,我这里给出自己想到的一种解法(不对就多多指教)。

 

我的思路:

1.把结点想成二维数组中的元素,起先所有结点都在二维数组的第0列,如下图:

 

1  
2  
3  
4  

2.1号结点和2号节点在同一列上,而它们之间是有边的,所以将1号节点右移一个单

 1  
2   
3   
4   

此时1所在的列没有和1结点相连的结点元素(下面全为空),所以1元素就移好了

再看2号元素,在第0列中,3元素是与2元素相连的,所以2号元素右移,如下

 

 1  
 2  
3   
4   

然而此时2号元素与刚刚的1号元素在同一列中,且1与2之间是有边的,所以2继续右移

 

 1  
  2 
3   
4   

这时候2就安全了

同理,3移动后

 

 1  
  2 
   3
4   

最后一个元素不管能不能在所在的列容下身,都必须右移,因为最后一个元素可能插到空里头,所以最后如下:

 

 1  
  2 
   3
  4 

 

移动元素部分就完成了,接下来分析这个二维数组:

 

每一列就是一种颜色,总共有3列有元素的列,所以一共需要三种颜色,1一种颜色,2,4一种颜色,3一种颜色。

 

另:实际上没必要造一个数组,用一个哈希表就行了,key纪录节点的值,value纪录结点所在的列,所以文章的标题是:虚拟二维数组求染色问题  下面是我的代码  java写的:

package test;


import java.util.*;
public class Test
{
    public static void main(String[] args)
    {
    	Scanner sc = new Scanner(System.in);
    	System.out.println("地图有几个区域?");
    	int n = sc.nextInt();
    	Map<Integer,Integer> map = new HashMap<>();
    	for(int i = 0;i<n;i++)
    	{
    		map.put(i, 0);
    	}
    	
    	int[][] a = new int[n][n];
    	for(int i = 0;i<n;i++)
    	{
    		System.out.println("第"+i+"个区域有几个相邻区域?");
    		int m = sc.nextInt();
    		System.out.println("依次输入与第"+i+"个区域相邻的区域号");
    		for(int j = 0;j<m;j++)
    		{
    			a[i][sc.nextInt()] = 1;
    		}
    	}
    	for(int i = 0;i<n;i++)
    	{
    		boolean hasMoved = true;
    		if(i == n-1)
    			map.put(n-1, 1);
    		while(hasMoved)
    		{
    			hasMoved = false;
    			for(int j = 0;j<n;j++)
    			{
    				if( (a[i][j] == 1||a[j][i] == 1)
    						&&map.get(j) == map.get(i))
    				{
    					map.put(i, map.get(i)+1 );
    					hasMoved = true;
    					break;
    				}
    			}
    		}
    	}
    	for(int i = 0;i<n;i++)
    	{
    		System.out.println("第"+i+"号区域涂上第"+map.get(i)+"号颜色");
    	}
    }
}

对于图:

输入输出如下:

地图有几个区域?
6
第0个区域有几个相邻区域?
3
依次输入与第0个区域相邻的区域号
1 2 3
第1个区域有几个相邻区域?
4
依次输入与第1个区域相邻的区域号
0 2 4 5
第2个区域有几个相邻区域?
4
依次输入与第2个区域相邻的区域号
0 1 3 4
第3个区域有几个相邻区域?
3
依次输入与第3个区域相邻的区域号
0 2 4
第4个区域有几个相邻区域?
4
依次输入与第4个区域相邻的区域号
1 2 3 5
第5个区域有几个相邻区域?
2
依次输入与第5个区域相邻的区域号
1 4
第0号区域涂上第1号颜色
第1号区域涂上第2号颜色
第2号区域涂上第3号颜色
第3号区域涂上第2号颜色
第4号区域涂上第1号颜色
第5号区域涂上第3号颜色

 

对于图:

输入输出如下:

地图有几个区域?
7
第0个区域有几个相邻区域?
3
依次输入与第0个区域相邻的区域号
1 2 3
第1个区域有几个相邻区域?
3
依次输入与第1个区域相邻的区域号
0 2 5
第2个区域有几个相邻区域?
5
依次输入与第2个区域相邻的区域号
0 1 3 4 5
第3个区域有几个相邻区域?
3
依次输入与第3个区域相邻的区域号
0 2 4
第4个区域有几个相邻区域?
4
依次输入与第4个区域相邻的区域号
2 3 5 6
第5个区域有几个相邻区域?
4
依次输入与第5个区域相邻的区域号
1 2 4 6
第6个区域有几个相邻区域?
2
依次输入与第6个区域相邻的区域号
4 5
第0号区域涂上第1号颜色
第1号区域涂上第2号颜色
第2号区域涂上第3号颜色
第3号区域涂上第2号颜色
第4号区域涂上第1号颜色
第5号区域涂上第4号颜色
第6号区域涂上第2号颜色

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值