算法笔记_177:历届试题 城市建设(Java)
目录
1 问题描述
C市中有n个比较重要的地点,市长希望这些地点重点被考虑。现在可以修一些道路来连接其中的一些地点,每条道路可以连接其中的两个地点。另外由于C市有一条河从中穿过,也可以在其中的一些地点建设码头,所有建了码头的地点可以通过河道连接。
栋栋拿到了允许建设的道路的信息,包括每条可以建设的道路的花费,以及哪些地点可以建设码头和建设码头的花费。
市长希望栋栋给出一个方案,使得任意两个地点能只通过新修的路或者河道互达,同时花费尽量小。
接下来m行,每行三个整数a, b, c,表示可以建设一条从地点a到地点b的道路,花费为c。若c为正,表示建设是花钱的,如果c为负,则表示建设了道路后还可以赚钱(比如建设收费道路)。
接下来一行,包含n个整数w_1, w_2, …, w_n。如果w_i为正数,则表示在地点i建设码头的花费,如果w_i为-1,则表示地点i无法建设码头。
输入保证至少存在一个方法使得任意两个地点能只通过新修的路或者河道互达。
1 2 4
1 3 -1
2 3 3
2 4 5
4 5 10
-1 10 10 1 1
对于50%的数据,1<=n<=100,1<=m<=1000,-50<=c<=50,w_i<=50;
对于70%的数据,1<=n<=1000;
对于100%的数据,1 <= n <= 10000,1 <= m <= 100000,-1000<=c<=1000,-1<=w_i<=1000,w_i≠0。
2 解决方案
此题主要考查Kruskal算法的运用,对于本题包含码头部分需要加一个状态顶点0与相应顶点连接,表示一条边。
注意:此处不单单是求最小生成树,其中权值为负数的边均要修,因为修这条边是百分之百赚钱的,在赚钱的基础上再求取最小生成树,确定每两个顶点均连通。
求取最小生成树时考虑两点:
(1)仅仅只有道路,此时共包含顶点1~n个顶点,顶点个数为n;
(2)包含码头,此处加一个额外状态顶点0,即顶点个数为n + 1,此时要特别注意码头最低要两个才有用,即包含顶点0的边最少要有两条。
下面代码在蓝桥系统中测评分为80分,原因:运行超时,用相应思想的C++代码为100分。(具体C++实现请见文末参考资料)

具体代码如下:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Scanner; public class Main {
public static int n, m;
public static int[] id;
public static ArrayList<edge> list = new ArrayList<edge>();
public static int result = Integer.MAX_VALUE; static class edge {
public int a;
public int b;
public int value; public edge(int a, int b, int value) {
this.a = a;
this.b = b;
this.value = value;
}
} class MyComparator implements Comparator<edge> {
public int compare(edge o1, edge o2) {
if(o1.value > o2.value)
return 1;
else if(o1.value < o2.value)
return -1;
return 0;
}
} public int find(int a) {
int root = a;
while(id[root] >= 0) {
root = id[root];
}
int i = 0, k = a;
while(k != root) {
i = id[k];
id[k] = root;
k = i;
}
return root;
} public void union(int a, int b) {
int rootA = find(a);
int rootB = find(b);
if(rootA == rootB)
return;
int num = id[rootA] + id[rootB];
if(id[rootA] < id[rootB]) {
id[rootB] = rootA;
id[rootA] = num;
} else {
id[rootA] = rootB;
id[rootB] = num;
}
} public void kruskal() {
Collections.sort(list, new MyComparator());
int temp = 0;
int count = 0;
int count1 = 0;//计算加入状态顶点0时,包含的边数目,若包含状态顶点0,则只是包含两条边 for(int i = 0;i < list.size();i++) {
edge p = list.get(i);
int a = p.a;
int b = p.b;
if(find(a) != find(b) && count < n - 1) {
temp += p.value;
union(a, b);
count++;
if(a == 0 || b == 0)
count1++;
} else if(p.value < 0) //此时,修这条路是一定赚钱的,所以必修
temp += p.value;
else if(count == n - 1 && p.value > 0)
break;
}
if(count == n - 1 && (count1 == 0 || count1 > 1))
result = Math.min(result, temp);
} public static void main(String[] args) {
Main test = new Main();
Scanner in = new Scanner(System.in);
n = in.nextInt();
m = in.nextInt();
id = new int[n + 1];
for(int i = 0;i <= n;i++)
id[i] = -1;
for(int i = 0;i < m;i++) {
int a = in.nextInt();
int b = in.nextInt();
int c = in.nextInt();
list.add(new edge(a, b, c));
}
test.kruskal(); //此处用于寻找不含码头的最后生成树得出的结果
for(int i = 0;i <=n;i++)
id[i] = -1;
int[] point = new int[n]; //使用码头连通
for(int i = 0;i < n;i++)
point[i] = in.nextInt();
for(int i = 0;i < n;i++) {
if(point[i] == -1)
continue;
list.add(new edge(0, i + 1, point[i])); //添加一个顶点0状态地点,所有码头均可到
}
n = n + 1; //此处是因为增加了一个状态顶点0,所以n要加1
test.kruskal(); //此处用于寻找包含码头的最小生成树的出的结果
System.out.println(result);
}
}
参考资料:
算法笔记_177:历届试题 城市建设(Java)的更多相关文章
- 算法笔记_186:历届试题 高僧斗法(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 古时丧葬活动中经常请高僧做法事.仪式结束后,有时会有“高僧斗法”的趣味节目,以舒缓压抑的气氛. 节目大略步骤为:先用粮食(一般是稻米)在地 ...
- 算法笔记_183:历届试题 九宫重排(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 如下面第一个图的九宫格中,放着 1~8 的数字卡片,还有一个格子空着.与空格子相邻的格子中的卡片可以移动到空格中.经过若干次移动,可以形成 ...
- 算法笔记_172:历届试题 波动数列(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 观察这个数列: 1 3 0 2 -1 1 -2 ... 这个数列中后一项总是比前一项增加2或者减少3. 栋栋对这种数列很好奇,他想知道长度 ...
- 算法笔记_196:历届试题 剪格子(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 如下图所示,3 x 3 的格子中填写了一些整数. +--*--+--+|10* 1|52|+--****--+|20|30* 1|**** ...
- 算法笔记_195:历届试题 错误票据(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 某涉密单位下发了某种票据,并要在年终全部收回. 每张票据有唯一的ID号.全年所有票据的ID号是连续的,但ID的开始数码是随机选定的. 因为 ...
- 算法笔记_194:历届试题 翻硬币(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 小明正在玩一个“翻硬币”的游戏. 桌上放着排成一排的若干硬币.我们用 * 表示正面,用 o 表示反面(是小写字母,不是零). 比如,可能情 ...
- 算法笔记_190:历届试题 幸运数(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 幸运数是波兰数学家乌拉姆命名的.它采用与生成素数类似的“筛法”生成 . 首先从1开始写出自然数1,2,3,4,5,6,.... 1 就是第 ...
- 算法笔记_188:历届试题 危险系数(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 抗日战争时期,冀中平原的地道战曾发挥重要作用. 地道的多个站点间有通道连接,形成了庞大的网络.但也有隐患,当敌人发现了某个站点后,其它站点 ...
- 算法笔记_187:历届试题 网络寻路(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 X 国的一个网络使用若干条线路连接若干个节点.节点间的通信是双向的.某重要数据包,为了安全起见,必须恰好被转发两次到达目的地.该包可能在任 ...
随机推荐
- IOS webView学习
本文简单介绍下在IOS中,webView的基本用法,也顺便强化下自己的基础知识----天明少羽爬楼梯 一.加载外部HTML 显示webView 报错:NSURLSession/NSURLConnect ...
- 虚拟信用卡 全球付, 工商银行国际E卡, Bancore, Entropay, Payoneer
虚拟信用卡 海外网购.购买国外域名空间.ebay等一些国外网站账号的激活这些情况都需要用到国际信用卡, 如果没有信用卡或者有信用卡但是对于安全性有所顾虑怎么办? 其实有一种东西叫做虚拟信用卡,正规银行 ...
- 转 Objective-C中不同方式实现锁(一)
为什么需要使用锁,当然熟悉多线程的你,自然不会对它觉得陌生. 那你在代码中是否很好的使用了锁的机制呢?你又知道几种实现锁的方法呢? 今天一起来探讨一下Objective-C中几种不同方式实现的锁,在这 ...
- Selenium2+python自动化29-js处理多窗口
前言 在打开页面上链接的时候,经常会弹出另外一个窗口(多窗口情况前面这篇有讲解:Selenium2+python自动化13-多窗口.句柄(handle)),这样在多个窗口之间来回切换比较复杂,那么有没 ...
- 用JavaScript,获取Table中指定的行、列
前言: 先要谢谢George Wing的慷慨赠书<悟透JavaScript>,让我更加感受到了技术交流的重要性,呵呵~ 进入正题,面试题中有一题:如何通过JavaScript获取Table ...
- FFMpeg开发使用
1.jjmpeg下载 https://code.google.com/p/jjmpeg/downloads/list 2.ffmpeg文档地址 https://www.ffmpeg.org/ 3.安卓 ...
- 关于SpringCloud微服务架构概念的一点理解
目前微服务是非常火的架构或者说概念,也是在构建大型互联网项目时采用的架构方式. 1.单体架构单体架构,是指将开发好的项目打成war包,然后发布到tomcat等容器中的应用. 假设你正准备开发一款与Ub ...
- [Swift] Swift3.0--GCD
reference to : http://www.jianshu.com/p/4c983388dca6 估计现在好多人在为这一块头疼,所以先来点干货. //最常用模板 //全局队列异步执行 Disp ...
- Rabbit MQ UI 重置 用户名 密码
新增admin用户 rabbitmqctl add_user newadmin s0m3p4ssw0rd rabbitmqctl set_user_tags newadmin administrato ...
- Depth of field --Circle of confusion 推导
https://en.wikipedia.org/wiki/Circle_of_confusion https://developer.download.nvidia.com/books/HTML/g ...