用局部替换方式求解最小生成树 java

从T=空集开始

for(图中每条边e)

       if 加入e不构成环,则 T=T+e

       else e‘ 是环上权重最大的边,T = T+e'

 

解:利用邻接表形式存储图,用另一张图,每一次向新图里面加入一条边,从加入边的顶点开始做dfs遍历。如果遇到后向边,就说明图中有环,找出最大的边,删掉该边,再加入边,继续dfs过程,直到所有边都加入。

这里图用hashmap存储,

static Map<Integer, LinkedList<Pair<Integer, Integer>>> graph = new HashMap<>();//邻接表存储图 ,pair存到达点和权重

初始化:

@SuppressWarnings({ "unchecked", "rawtypes" })
	public static void ini() {
		System.out.println("请输入顶点数:");
		v = scanner.nextInt(); 
		visited = new int[v];
		pre = new int[v]; 
		
		System.out.println("请输入边数和各条边以及权重:");
		e = scanner.nextInt();
		
		for(int i=0; i<e; i++) 
		{
			resGraph.put(i, new LinkedList<>()); 
			graph.put(i, new LinkedList<>()); 
		}
		
		for(int i=0; i<e; i++)
		{
			int from = scanner.nextInt();
			int to = scanner.nextInt();
			int weight = scanner.nextInt();
			if(weight<=0) {
				System.out.println("权重必须大于0!\n重新输入:");
				weight = scanner.nextInt();
			}
			graph.get(from).add(new Pair(to, weight));
			graph.get(to).add(new Pair(from, weight));//双向添加
			//DFS(from, visited, graph);
		}
		printGrapg(graph);
	}

深度优先搜索:

//dfs遍历
	public static void DFS(int start, int[] visited ,Map<Integer, LinkedList<Pair<Integer, Integer>>> graph) {
		for(int i=0; i<v; i++) {
			visited[i] = white;//初始化都是白色
			pre[i] = -1;//没有前驱点 
		}
		dfsVisit(0, visited, graph);//从0开始遍历
	}
	
	//dfs递归部分
	public static void dfsVisit(int start,int[] visited, Map<Integer,LinkedList<Pair<Integer, Integer>>> graph) {
		time++;
		visited[start] = gray;
		for(Pair<Integer, Integer> p:graph.get(start))
		{
			if(visited[p.getKey()]==gray && p.getKey()!=pre[start])//是灰色出现了环,后向边
			{
				findMax(start, p.getKey(), p.getValue(), graph);//标记
			}
			if(visited[p.getKey()]==white)
			{
				pre[p.getKey()] = start;
				dfsVisit(p.getKey(), visited, graph);
			}			
		}
		visited[start] = black;
		time++;
	}

 

找最大权重的边:这里用pre数组记录了每一个点的前向点,根据此来找到环和最大边

//找最大权值的边
	public static void findMax(int end, int start, int weight, Map<Integer,LinkedList<Pair<Integer, Integer>>> graph) { 
		//System.out.println("bugbugbugbugbug:"+end+" "+start+" "+weight);
		int a = pre[end], endP = end;
		int maxKey = 0, w=0, maxEnd=start;
		while(a!=pre[start]) {
			w = findWeight(endP, a); 
			if(maxKey <= w) {
				maxEnd = endP;
				maxKey = w;
			}
			endP = a;
			a = pre[endP];
		}
		if(maxKey>weight) {//最大的是树边里面的
			//isMax.put(maxEnd, pre[maxEnd]);
			delete(graph, maxEnd, pre[maxEnd]);
			delete(graph, pre[maxEnd], maxEnd);
		}else {
			//isMax.put(end, start);//最大边是该后向边
			delete(graph, end, start);
			delete(graph, start, end);
		}
		 
	}

主函数:

for(int i=0; i<v;i++)
		{
			for(int j=0; j<graph.get(i).size(); j++)
			{
				
					from = i; to = graph.get(i).get(j).getKey(); w = graph.get(i).get(j).getValue();
					if(from<to)
					{
					resGraph.get(from).add(new Pair<Integer, Integer>(to, w));//每次添加一条边
					resGraph.get(to).add(new Pair<Integer, Integer>(from, w));
					DFS(to, visited, resGraph);
				}
				
			}
		}
		int count=0;
		for(int i=0; i<v; i++) {
			System.out.print("\n"+i+" :: ");
			for(Pair<Integer, Integer> p : resGraph.get(i))
			{
				System.out.print("  "+i+"->"+p.getKey()+" "+p.getValue());//i->p 3
				count+=p.getValue();
			}
		}
		System.out.println(count/2);

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值