旅行计划 - Travel Plan - Kruskal

旅行计划

(测试用例总数:X个,1.5秒(C/C++),2秒(JAVA)/内存限制:256 M,Stack 1 M)

琳恩正在计划前往S国进行K次旅行

S国有N座城市,城市之间通过M条道路连接着。琳恩可从任意一座城市前往另一座城市,移动时,每条道路均会产生通行费,所以她需要支付费用。

琳恩计划在K次旅行期间,通过利用最少的道路来访问N座城市,而每座城市至少需要访问一次。如果按照如上的方式旅行时,存在多种方案的话,琳恩想找出其中花费最低的出行方案作为旅行计划。

琳恩可以选择K次旅行时的出发城市,但她必须要返回出发城市才能结束此次旅行。请帮助琳恩求出旅行时所需要的最低费用。

 

 如上图所示,假设分成两次来旅行六座城市,第一次旅行是从城市①出发,沿着 ①→②→③→②→① 的路径旅行,这时她利用了两条道路旅行了三座城市,最终花费了8。(再次途经同一条道路时,虽然利用的道路次数不会增加,但需要再次支付通行费)。如果沿着 ①→②→③→① 的路径旅行时,虽然产生的费用会更低,花费是7,但她不会采取该路线,因为该路线需要经过更多的道路。第二次旅行是从城市⑥出发,沿着⑥→④→⑥→⑤→⑥旅行,这时她仅利用了两条道路旅行了三座城市,花费为18。按照以上计划,通过两次旅行,她只需利用四条道路便可旅行所有的六座城市,花费为26。这是琳恩想要的最佳旅行方案之一。

 

[限制条件]

1.城市数量N为介于3到100,000之间的整数。

2.道路数量M为介于N-1到200,000之间的整数。

3.旅行次数K为介于2到N之间的整数。

4.道路通行费C为介于1到100,000之间的整数。

5.再次途径相同道路时,仍然需要支付通行费。

 

[输入]

首先给出测试用例数量T,接着给出T种测试用例。每个测试用例的第一行空格区分给出城市数N、道路数M以及旅行次数K。第二行开始,通过M行,每行按照A B C(城市A,城市B,通行费C)的格式空格区分给出道路信息。

 

[输出]

每个测试用例输出一行。首先输出“#x”(x为测试用例编号,从1开始),加一个空格,输出K 次旅行所需要的最低费用。

 

[输入输出 示例]

(输入)

2
6 10 2
1 2 2
1 3 3
1 5 5
2 4 6
2 3 2
3 4 5
3 6 5
3 5 5
4 6 5
5 6 4
6 10 3
1 2 2
1 3 3
1 5 5
2 4 6
2 3 2
3 4 5
3 6 5
3 5 5
4 6 5
5 6 4

(输出)

#1 26
#2 16

 

思路分析:
通过利用最少的道路来访问N座城市,而每座城市至少需要访问一次 ,由此可推断出是求最小生成树,可使用Kruskal。
她必须要返回出发城市才能结束此次旅行,即距离=最小生成树的距离*2
K次旅行,说明是K个连通分量,说明只需要循环N-K次

 

package graph;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Comparator;
import java.util.StringTokenizer;

/**
 * 思路分析:
 * 通过利用最少的道路来访问N座城市,而每座城市至少需要访问一次 ,由此可推断出是求最小生成树,可使用Kruskal。
 * 她必须要返回出发城市才能结束此次旅行,即距离=最小生成树的距离*2
 * K次旅行,说明是K个连通分量,说明只需要循环N-K次
 * 
 * @author XA-GDD
 *
 */
public class TravelPlan_0720 {
	static int T,N,M,K;
	static int _Max_N = 100000;
	static int _Max_M = 200000;
	static TravelPlanNode [] srcArr = new TravelPlanNode[_Max_M];
	static int [] parent = new int[_Max_N+1];
	static int count;
	static long ans;
	public static void main(String[] args) throws IOException {
		System.setIn(new FileInputStream("D:\\workspace\\eclipse-workspace\\sw_pro\\test_case\\sample_input_0720.txt"));
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
	    StringTokenizer st = new StringTokenizer(br.readLine());
		T = Integer.parseInt(st.nextToken());
	    for(int testCase = 1; testCase<=T;testCase++) {   	
	    	st = new StringTokenizer(br.readLine());
	    	N = Integer.parseInt(st.nextToken());
	    	M = Integer.parseInt(st.nextToken());
	    	K = Integer.parseInt(st.nextToken());
	    	init();
	    	for(int i=0;i<M;i++) {
	    		st = new StringTokenizer(br.readLine());
	    		srcArr[i] = new TravelPlanNode(Integer.parseInt(st.nextToken()),Integer.parseInt(st.nextToken()),Integer.parseInt(st.nextToken()));
	    	}
	    	
	    	//根据权值排序
	    	Arrays.sort(srcArr,0,M,new comTravelPlan());
	    	
	    	for(int i=0;i<M;i++) {
	    		if(count==N-K) {
	    			break;
	    		}
	    		if(find(srcArr[i].start)!=find(srcArr[i].end)) {
	    			union(srcArr[i].start,srcArr[i].end);
	    			count++;
	    			ans += (long)srcArr[i].cost*2;
	    		}
	    	}
	    	System.out.println("#"+testCase+" "+ans);
	    }
	}
	
	static void init() {
		Arrays.fill(srcArr, null);
		for(int i=0;i<N;i++) {
			parent[i]=i;
		}
		ans=0L;
		count=0;
	}
	
	static int find(int n) {
		if(parent[n]==n) return n;
		return parent[n] = find(parent[n]);
	}
	
	static void union(int a, int b) {
		int pa = find(a);
		int pb = find(b);
		if(pa==pb) return;
		if(pa>pb) {
			parent[pb]=pa;
		}else {
			parent[pa]=pb;
		}
		
	}

}
class TravelPlanNode{
	int start;
	int end;
	int cost;
	TravelPlanNode(int start, int end ,int cost){
		this.start=start;
		this.end=end;
		this.cost=cost;
	}
}

class comTravelPlan  implements Comparator<TravelPlanNode>{
	@Override
	public int compare(TravelPlanNode o1, TravelPlanNode o2) {
		return o1.cost-o2.cost;
	}
	
}

  

posted @ 2022-01-20 21:18  晓暮云  阅读(795)  评论(0)    收藏  举报