算法笔记_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 国的一个网络使用若干条线路连接若干个节点.节点间的通信是双向的.某重要数据包,为了安全起见,必须恰好被转发两次到达目的地.该包可能在任 ...
随机推荐
- git服务器安装和配置
http://www.cnblogs.com/dee0912/p/5815267.html
- SimpleDateFormat in Java is not Thread-Safe Use Carefully
SimpleDateFormat in Java very common and used to format Date to String and parse String into Date i ...
- 音频视频解决方案:GStreamer/ffmpeg/ffdshow/directshow/vfw
音频视频编程相关:GStreamer/ffmpeg/directshow/vfw linux和window下几种流行的音频视频编程框架作一个总结,防止自己迷惘,免于晕头转向. 一.GStreamer ...
- .NET:CLR via C# The Interlocked Anything Pattern
Many people look at the Interlocked methods and wonder why Microsoft doesn't create a richer set of ...
- dao层的泛型实现(2种方法)
一: package com.wzs.test2.dao; import java.util.List; public interface CommonDAO { public <T> v ...
- [Android Pro] Swift 3.0多线程
本文只介绍Grand Central Dispath(GCD) 中央调度 个人认为一个GCD就够用了,可能是改版或是其他的在找之前写的多线程方法时发现不能用了,看文档之后发现改了,现在看上去更加简单易 ...
- u-boot支持yaffs映像烧写的补丁
u-boot的nand flash驱动有两个版本,似乎是以u-boot1..5为分界点的,之前的版本使用的是自己写的nand flash驱动,而后面的版本使用的是linux内核中nand flash的 ...
- mac下使用brew安装java等应用
可以使用brew安装很多应用,比如java,idea,iterms,sublime brew tap caskroom/versions 将会安装新的brew仓库源brew cask install ...
- 谁能用通俗的语言解释一下什么是 RPC 框架
转载自知乎:https://www.zhihu.com/question/25536695 知乎上很多问题的答案还是很好的,R大就经常在上面回答问题~ 谁能用通俗的语言解释一下什么是 RPC 框架? ...
- 数学图形之SineSurface与粽子曲面
SineSurface直译为正弦曲面.这有可能和你想象的正弦曲线不一样.如果把正弦曲线绕Y轴旋转,得到的该是正弦波曲面.这个曲面与上一节中的罗马曲面有些相似,那个是被捏过的正四面体,这个则是个被捏过正 ...