Ztree使用教程
这两天项目需要写一个树形帮助,学习了我们项目组的老师的Ztree的树的写法,实现了这个帮助,下面来总结一下Ztree的用法。
(也是参考的一篇csdn上的博客了)
zTree 是一个依靠 jQuery 实现的多功能 “树插件”。被广泛应用在系统的权限管理中,本文讲解zTree的一般应用
zTree 官网 http://www.treejs.cn/v3/main.php#_zTreeInfo
1、zTree 官网下载 ztree
下载好后放到项目相关目录下
2、编写相关代码
引入相关js 、 css 文件,代码如下:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script type="text/javascript" src="js/jquery-3.2.1.min.js" ></script>
<link rel="stylesheet" href="ztree/css/metroStyle/metroStyle.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" src="ztree/js/jquery.ztree.all.min.js" ></script>
</head>
<body> </body>
</html>
上述代码中的 css 还可以引入如下两种、它们分别具有不同的样式
<link rel="stylesheet" href="ztree/css/zTreeStyle/zTreeStyle.css" rel="stylesheet" type="text/css" />
或
<link rel="stylesheet" href="ztree/css/awesomeStyle/awesome.css" rel="stylesheet" type="text/css" />
快速实现一个简单的树,请看如下代码,相关配置说明已写在代码中
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script type="text/javascript" src="js/jquery-3.2.1.min.js" ></script>
<link rel="stylesheet" href="ztree/css/metroStyle/metroStyle.css" rel="stylesheet" type="text/css" />
<!--
其他两种css风格样式
<link rel="stylesheet" href="ztree/css/zTreeStyle/zTreeStyle.css" rel="stylesheet" type="text/css" />
<link rel="stylesheet" href="ztree/css/awesomeStyle/awesome.css" rel="stylesheet" type="text/css" />
-->
<script type="text/javascript" src="ztree/js/jquery.ztree.all.min.js" ></script>
</head>
<body>
<div>
<ul id="treeDemo" class="ztree"></ul>
</div>
<script>
var settingss = {
data: {
simpleData: {
enable: true, //true 、 false 分别表示 使用 、 不使用 简单数据模式
idKey: "id", //节点数据中保存唯一标识的属性名称
pIdKey: "parentId", //节点数据中保存其父节点唯一标识的属性名称
rootPId: -1 //用于修正根节点父节点数据,即 pIdKey 指定的属性值
},
key: {
name: "menuName" //zTree 节点数据保存节点名称的属性名称 默认值:"name"
}
},
check:{
enable:true, //true 、 false 分别表示 显示 、不显示 复选框或单选框
nocheckInherit:true //当父节点设置 nocheck = true 时,设置子节点是否自动继承 nocheck = true
}
}; //数据
var zNodes = [
//注意,数据中的 menuName 必须与 settingss 中key 中定义的name一致,否则找不到
{menuName:"父节点1", open:true, children:[
{menuName:"子节点1"}, {menuName:"子节点2"}]},
{menuName:"父节点2", open:true, children:[
{menuName:"子节点3"}, {menuName:"子节点4"}]}
]; zTreeObj = $.fn.zTree.init($("#treeDemo"), settingss, zNodes); //初始化树
zTreeObj.expandAll(true); //true 节点全部展开、false节点收缩
</script>
</body>
</html>
运行效果如下图
3、使用ajax获取数据
实际项目开发中,数据往往是从后台服务器获取的,而不是在前端写死的。如何实现ajax获取数据,请看如下代码
数据库表结构及数据如下
后台接口代码如下
mapper层
import java.util.List;
import org.apache.ibatis.annotations.Select;
import com.che.pri.bean.MenuTest; public interface MenuTestMapper { @Select("select id as id, parent_id as parentId, menu_name as menuName from menu_test")
List<MenuTest> getMenuTestList(); }
controller层
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.che.pri.mapper.MenuTestMapper;
@Controller
public class MenuTestController { @Autowired
private MenuTestMapper menuTestMapper; @ResponseBody
@RequestMapping("/getMenuTestList")
public Object getMenuTestList() {
Map<String, Object> map = new HashMap<String, Object>();
map.put("menulists", menuTestMapper.getMenuTestList());
return map;
}
}
html代码如下
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script type="text/javascript" src="js/jquery-3.2.1.min.js" ></script>
<link rel="stylesheet" href="ztree/css/metroStyle/metroStyle.css" rel="stylesheet" type="text/css" />
<!--
其他两种css风格样式
<link rel="stylesheet" href="ztree/css/zTreeStyle/zTreeStyle.css" rel="stylesheet" type="text/css" />
<link rel="stylesheet" href="ztree/css/awesomeStyle/awesome.css" rel="stylesheet" type="text/css" />
-->
<script type="text/javascript" src="ztree/js/jquery.ztree.all.min.js" ></script>
</head>
<body>
<div>
<ul id="treeDemo" class="ztree"></ul>
</div>
<script>
var settingss = {
data: {
simpleData: {
enable: true, //true 、 false 分别表示 使用 、 不使用 简单数据模式
idKey: "id", //节点数据中保存唯一标识的属性名称
pIdKey: "parentId", //节点数据中保存其父节点唯一标识的属性名称
rootPId: -1 //用于修正根节点父节点数据,即 pIdKey 指定的属性值
},
key: {
name: "menuName" //zTree 节点数据保存节点名称的属性名称 默认值:"name"
}
},
check:{
enable:true, //true 、 false 分别表示 显示 、不显示 复选框或单选框
nocheckInherit:true //当父节点设置 nocheck = true 时,设置子节点是否自动继承 nocheck = true
}
}; $(document).ready(function(){
$.ajax({
type:"get",
url:"http://localhost:8089/getMenuTestList",
async:true,
success:function(res){ zTreeObj = $.fn.zTree.init($("#treeDemo"), settingss, res.menulists); //初始化树
zTreeObj.expandAll(true); //true 节点全部展开、false节点收缩
}
});
});
</script>
</body>
</html>
运行效果如下
4、设置默认选中节点
在开发中,有时我们需要默认选中一些节点。比如修改用户角色或权限时,就会有这样的需求,如何对ztree的节点进行默认选中,请看如下代码
var node = zTreeObj.getNodeByParam("id", 7);
zTreeObj.checkNode(node, true, false);
通过每一条节点数据的 id 进行设置
具体看如下代码
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<script type="text/javascript" src="js/jquery-3.2.1.min.js" ></script>
<link rel="stylesheet" href="ztree/css/metroStyle/metroStyle.css" rel="stylesheet" type="text/css" />
<!--
其他两种css风格样式
<link rel="stylesheet" href="ztree/css/zTreeStyle/zTreeStyle.css" rel="stylesheet" type="text/css" />
<link rel="stylesheet" href="ztree/css/awesomeStyle/awesome.css" rel="stylesheet" type="text/css" />
-->
<script type="text/javascript" src="ztree/js/jquery.ztree.all.min.js" ></script>
</head>
<body>
<div>
<ul id="treeDemo" class="ztree"></ul>
</div>
<script>
var settingss = {
data: {
simpleData: {
enable: true, //true 、 false 分别表示 使用 、 不使用 简单数据模式
idKey: "id", //节点数据中保存唯一标识的属性名称
pIdKey: "parentId", //节点数据中保存其父节点唯一标识的属性名称
rootPId: -1 //用于修正根节点父节点数据,即 pIdKey 指定的属性值
},
key: {
name: "menuName" //zTree 节点数据保存节点名称的属性名称 默认值:"name"
}
},
check:{
enable:true, //true 、 false 分别表示 显示 、不显示 复选框或单选框
nocheckInherit:true //当父节点设置 nocheck = true 时,设置子节点是否自动继承 nocheck = true
}
}; $(document).ready(function(){
$.ajax({
type:"get",
url:"http://localhost:8089/getMenuTestList",
async:true,
success:function(res){ zTreeObj = $.fn.zTree.init($("#treeDemo"), settingss, res.menulists); //初始化树
zTreeObj.expandAll(true); //true 节点全部展开、false节点收缩 //设置选中节点
var node = zTreeObj.getNodeByParam("id", 7);
zTreeObj.checkNode(node, true, false); var node = zTreeObj.getNodeByParam("id", 1);
zTreeObj.checkNode(node, true, false); var node = zTreeObj.getNodeByParam("id", 4);
zTreeObj.checkNode(node, true, false);
}
});
});
</script>
</body>
</html>
运行效果
其他内容可参考官网API
在这里声明一下版权
————————————————
版权声明:本文为CSDN博主「悟世君子」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wsjzzcbq/article/details/83029532
以上都是学习人家写的内容了,我介绍一下我在项目中对Ztree的一些理解。
首先,我需要写一个js让我跳到我想选择的树的页面里面去,并且从树的页面里面获取到我所需要的返回值。
// 选择员工
function selectDeviceType() {
var msg = "选择人员";
$.dialog({
type: 'iframe',
url: context + "/jsp/genersoft/public/health/HealthRyDepartment.jsp",
title: msg,
width: 580,
height: 400,
onclose: function () {
var nodes = this.returnValue;
$("#healthUserId").val(nodes[0].ORGAN_ID);
$("#username").val(nodes[0].ORGAN_NAME);
$("#healthOrgId").val(nodes[0].GRANDPA_ID);
$("#departmentname").val(nodes[0].GRANDPA_NAME);
$("#username").change();
}
});
}
接下来,就是我们选择帮助的页面,在这个页面里,需要初始化一下Ztree,构造一下Ztree的数据属性,写个ajax,给他一个后台的url,让他查数据,返回到前台来,再构造这个树。
事先需要引一些js
<script type="text/javascript" src="<l:asset path='jquery.js'/>"></script>
<script type="text/javascript" src="<l:asset path='bootstrap.js'/>"></script>
<script type="text/javascript" src="<l:asset path='form.js'/>"></script>
<script type="text/javascript" src="<l:asset path='ui.js'/>"></script>
<script type="text/javascript" src="<l:asset path='loushang-framework.js'/>"></script>
<script type="text/javascript" src="<l:asset path='i18n.js'/>"></script>
<script type="text/javascript" src="<l:asset path='ztree.js'/>"></script>
然后,初始化Ztree,构造这个树。
<SCRIPT LANGUAGE="JavaScript">
var context = "<l:assetcontext/>";
var dialog = parent.dialog.get(window);
var zTreeObj;
var setting = { check: {
enable: true,
chkStyle: "radio",
radioType: "all",
chkboxType: {"Y": "s", "N": "s"}
}
}; function filter(treeId, parentNode, childNodes) {
if (!childNodes) return null;
for (var i = 0, l = childNodes.length; i < l; i++) {
childNodes[i].name = childNodes[i].name.replace(/\.n/g, '.');
}
return childNodes;
} // zTree 的数据属性,深入使用请参考 API 文档(zTreeNode 节点数据详解)
var zNodes = [
{
name: "test1",
open: true,
children: [
{
name:"test1_1",
open:true,
children: [
{name: "test1_1_1"},
{name: "test1_1_2"}
]
},
{
name:"test1_2",
open:true,
children: [
{name: "test1_2_1"},
{name: "test1_2_2"}
]
}, ]
},
{
name: "test2",
open: true,
children: [
{
name:"test2_1",
open:true,
children: [
{name: "test2_1_1"},
{name: "test2_1_2"}
]
},
{
name:"test2_2",
open:true,
children: [
{name: "test2_2_1"},
{name: "test2_2_2"}
]
}, ]
},
]; $(document).ready(function () {
$.ajax({
type: "POST",
url: context + "/service/health/treeData2",
data: {},
dataType: "json",
aysn: false,
success: function (respMsg) {
zNodes = respMsg;
zTreeObj = $.fn.zTree.init($("#treeDemo"), setting, zNodes);
var node = zTreeObj.getNodeByParam("name", '${param.name}', null);
if (node){//判断有查询到节点
//方法一:
// $("#"+node.tId+"_a").click();//点击查询到的节点
//方法二:
zTreeObj.selectNode(node,true);//选
// node.checked = true;
// zTreeObj.updateNode(node);
}}
});
// var zTreeMenu = $.fn.zTree.getZTreeObj("treeDemo");//根据treeID(zTree的DOM容器的id)获取
//zTree对象的方法,必须初始化zTree才可以使用此方法
// var treeObj = $.fn.zTree.getZTreeObj("tree");
// var node = zTreeObj.getNodeByParam("id", 1, null);
// var node=zTreeObj.getNodeByParam('name',,null); // 确定按钮
$("#confirm").click(function () {
confirm();
}); // 取消按钮
$("#clear").click(function () {
clear();
});
}); // 确定按钮
function confirm() {
var msg = L.getLocaleMessage("bsp.organ.053", "请选择单个节点!");
var selectedNodes = zTreeObj.getCheckedNodes();
if (selectedNodes.length != 1) {
$.sticky(msg, {
autoclose: 1000,
position: "center",
style: "warning"
});
return false;
}
if(selectedNodes["0"].STRU_LEVEL!="4"){
$.sticky("请选择职工", {
autoclose: 1000,
position: "center",
style: "warning"
});
return false;
} dialog.close(selectedNodes);
dialog.remove();
} // 取消
function clear() {
var dialog = parent.dialog.get(window);
dialog.close("clear");
dialog.remove();
return false;
}
</SCRIPT>
</HEAD>
<BODY>
<div>
<ul id="treeDemo" class="ztree"></ul>
<div class="foot">
<div class="btnGroup">
<button id="confirm" type="button" class="btn ue-btn"><spring:message code="bsp.organ.046"
text="确定"/></button>
<button id="clear" type="button" class="btn ue-btn"><spring:message code="bsp.organ.048"
text="清除"/></button>
</div>
</div>
</div>
</BODY>
</HTML>
跳后台url,并对数据做一下拼接。
Contrller层
@Controller
@RequestMapping(value = "/health")
public class HealthController {
@Autowired
private IHealthService healthService;
/**
* 列表跳转页面
*
* @return 列表页面
*/
@RequestMapping
public String queryHealth() {
return "genersoft/public/health/healthQuery";
} @RequestMapping({"/treeData2"})
@ResponseBody
public List treeData2(HttpServletRequest req) {
return healthService.getTypeTreeData2("");
} }
Service层
@Service("healthService")
public class HealthServiceImpl implements IHealthService{ @Autowired
private HealthMapper healthMapper;
@Override
@Override
public List getTypeTreeData2(String struId) {
// TODO Auto-generated method stub
List<Map<String,Object>> list = healthMapper.getTreeData2();
List<Map> resList = new ArrayList<>();
//单位list
List<Map<String,Object>> UnitList=new ArrayList<Map<String,Object>>();
//部门list
List<Map<String,Object>> DepartmentList=new ArrayList<Map<String,Object>>();
//岗位list
List<Map<String,Object>> PostList=new ArrayList<Map<String,Object>>();
//人员list
List<Map<String,Object>> PersonList=new ArrayList<Map<String,Object>>();
for(Map<String,Object> unit:list) {
if(Integer.parseInt(String.valueOf(unit.get("STRU_LEVEL")))==1) {
UnitList.add(unit);
}
}
for(Map<String,Object> department:list) {
if(Integer.parseInt(String.valueOf(department.get("STRU_LEVEL")))==2) {
DepartmentList.add(department);
}
}
for(Map<String,Object> post:list) {
if(Integer.parseInt(String.valueOf(post.get("STRU_LEVEL")))==3) {
PostList.add(post);
}
}
for(Map<String,Object> person:list) {
if(Integer.parseInt(String.valueOf(person.get("STRU_LEVEL")))==4) {
PersonList.add(person);
}
}
List<Map<String, Object>> temp1List=new ArrayList<Map<String, Object>>();
List<Map<String, Object>> temp3List=new ArrayList<Map<String, Object>>();
List<Map<String, Object>> temp5List=new ArrayList<Map<String, Object>>();
for(Map<String,Object> temp6:DepartmentList) {
for(Map<String, Object> temp1:PostList) {
List<Map<String,Object>> greatgrandsonList=new ArrayList<Map<String,Object>>();
greatgrandsonList.clear();
for(Map<String,Object> temp2:PersonList) {
if(temp2.get("PARENT_ID").equals(temp1.get("ORGAN_ID"))) {
temp2.put("name",temp2.get("ORGAN_NAME"));
temp2.put("PARENT_NAME", temp1.get("ORGAN_NAME"));
if(temp1.get("PARENT_ID").equals(temp6.get("ORGAN_ID"))) {
temp2.put("GRANDPA_ID", temp6.get("ORGAN_ID"));
temp2.put("GRANDPA_NAME", temp6.get("ORGAN_NAME"));
}
greatgrandsonList.add(temp2);
}
}
temp1.put("children", greatgrandsonList);
temp1List.add(temp1);
}
}
System.out.println(temp1List);
System.out.println(1);
for(Map<String,Object> temp3:DepartmentList) {
List<Map<String,Object>> grandsonList=new ArrayList<Map<String,Object>>();
grandsonList.clear();
for(Map<String,Object> temp4:PostList) {
if(temp4.get("PARENT_ID").equals(temp3.get("ORGAN_ID"))) {
temp4.put("name",temp4.get("ORGAN_NAME"));
temp4.put("PARENT_NAME", temp3.get("ORGAN_NAME"));
grandsonList.add(temp4);
}
}
temp3.put("children", grandsonList);
//System.out.println(temp3);
temp3List.add(temp3);
}
System.out.println(temp3List);
System.out.println(1);
for(Map<String,Object> temp5:UnitList) {
List<Map<String,Object>> sonList=new ArrayList<Map<String,Object>>();
temp5.put("name",temp5.get("ORGAN_NAME"));
sonList.clear();
for(Map<String,Object> temp6:DepartmentList) {
if(temp6.get("PARENT_ID").equals(temp5.get("ORGAN_ID"))) {
temp6.put("name",temp6.get("ORGAN_NAME"));
temp6.put("PARENT_NAME", temp5.get("ORGAN_NAME"));
sonList.add(temp6);
}
}
temp5.put("children", sonList);
//System.out.println(temp5);
temp5List.add(temp5);
}
System.out.println(temp5List);
resList.addAll(temp5List);
return resList;
}
}
这个地方有几个点需要注意一下:
1.让他返回成一个父亲节点带着一个子节点的数据格式,要对数据进行一个拼接,返回数据的格式是如下的形式
[{STRU_ID=1, ORGAN_ID=1,
children=[{STRU_ID=2, ORGAN_ID=2,
children=[{STRU_ID=3, ORGAN_ID=3,
children=[{STRU_ID=4, GRANDPA_ID=2, ORGAN_ID=4, PARENT_NAME=岗位, name=a, STRU_LEVEL=4, ORGAN_NAME=a,
PARENT_ID=3, GRANDPA_NAME=2}]
}]
}]
}]
他的下一层规定写为children,这个是Ztree的数据属性,最好写死写成children。
2.在后台拼接的时候,需要给每个节点的name属性附上值
temp5.put("name",temp5.get("ORGAN_NAME"));
如果不给name赋值,则在前台显示的时候会出现undefined的情况。
3.然后是获取选择节点的属性值的方法,如下:
var selectedNodes = zTreeObj.getCheckedNodes();
其他的就没什么了,that's all,暂时写到这,想起来再补充。
Ztree使用教程的更多相关文章
- ztree实用教程
首先导入ztree ztree是建立在jquery的基础上的 <link href="js/zTree_v3-master/css/zTreeStyle/zTreeStyle.css& ...
- zTree的使用教程
1.首先去官网下载http://www.ztree.me/v3/main.php#_zTreeInfo 2.之后引入: <script src="js/jquery.ztree.all ...
- java菜鸟篇<四> ZTree入门篇
今天准备入手ZTree,于是在百度上搜了搜,找到了开源网址和一些大神们的教程,于是乎下午开始了组织树(ZTree)的练习 初步完整的作品是这个样子的: 1.咱们要去这个工具的开源网里找下载的东西: ( ...
- Angular整合zTree
1 前提准备 1.1 新建一个angular4项目 参考博文:点击前往 1.2 去zTree官网下载zTree zTree官网:点击前往 三少使用的版本:点击前往 2 编程步骤 从打印出zTree对象 ...
- zTree静态树与动态树的用法——(七)
0.[简介] zTree 是利用 JQuery 的核心代码,实现一套能完成大部分常用功能的 Tree 插件 兼容 IE.FireFox.Chrome 等浏览器 在一个页面内可同时生成多个 Tree 实 ...
- ztree案例笔记:用户不规范操作导致添加不了节点的问题
我使用ztree开发了简码"万能助手",经过一段时间的观察,发现有个别用户不看教程就开始操作,总能给我折腾出一些让人哭笑不得的问题. 比如,把某个根栏目里的节点全删除,然后发现添加 ...
- 项目中jquery插件ztree使用记录
最近公司要求做一个关于后台的管理系统.在这个mvvm模式横行的年代,虽然这里用jquery做项目可能有点不符合时代的潮流,但是管他呢,能做出来先在说呗(公司以后要改用angular或者vue来统一前端 ...
- [译]聊聊C#中的泛型的使用(新手勿入) Seaching TreeVIew WPF 可编辑树Ztree的使用(包括对后台数据库的增删改查) 字段和属性的区别 C# 遍历Dictionary并修改其中的Value 学习笔记——异步 程序员常说的「哈希表」是个什么鬼?
[译]聊聊C#中的泛型的使用(新手勿入) 写在前面 今天忙里偷闲在浏览外文的时候看到一篇讲C#中泛型的使用的文章,因此加上本人的理解以及四级没过的英语水平斗胆给大伙进行了翻译,当然在翻译的过程中发 ...
- 《JQuery常用插件教程》系列分享专栏
<JQuery常用插件教程>已整理成PDF文档,点击可直接下载至本地查阅https://www.webfalse.com/read/201719.html 文章 使用jquery插件实现图 ...
随机推荐
- 05-SV面向对象编程基础
1.测试平台的构建 发生器(generator):创建事务并且将它们传给下一级 驱动器(drive):与设计进行会话 监视器(monitor):捕获设计返回的事务 计分板(scoreboard):将捕 ...
- Android 基础知识 -- Intent
Intent (意图) Android通信的桥梁,可以通过Intent启动Activity , Service , 发送指定广播到Receiver <1> 启动Activity : sta ...
- 在MATLAB R2018b中配置VLFeat
在MATLAB R2018b中配置VLFeat 作者:凯鲁嘎吉 - 博客园 http://www.cnblogs.com/kailugaji/ VLFeat官网:http://www.vlfeat.o ...
- Vue中axios有关请求头的几点小结
在Vue前端中向后端发起http请求会有着两种写法:一种是在vue文件中直接导入axios模板,另外一种是使用Vue的属性$http. 1.在第一种方式中,在同一个工程中所添加的vue文件直接使用ax ...
- ST表求区间最值
#include<bits/stdc++.h> #define ll long long #define lowbit(x) x&-x using namespace std; ; ...
- [Arc083D/At3535] Restoring Road Network - 最短路,结论
[Arc083D/At3535] 有 \(N\) 个城市,城市与城市之间用长度为整数的无向道路连接. 现有一考古学家找到了一张 \(N×N\) 的表 \(A\) ,这张表代表了这 \(N\) 座城市两 ...
- S3C2440的时钟原理
Crystal 无源晶体Oscillator 有源晶体(里面有有源器件) 无源晶振内只有一片按一定轴向切割的石英晶体薄片,供接入运放(或微处理器的XTAL端) 以形成振荡.有源晶振内带运放,工作在最佳 ...
- Pandownload---windows下几乎无敌的网盘下载神器
近几天光顾着mac了,今天咱来聊聊Windows. 这个就不多说了,直接贴图. 网页版截图. 电脑版截图. 网页版2020.2.1的时候是失效的,别问我为什么不现在测试,用不着. 不用担心不知道密码, ...
- vue 动态组件的传值
vue项目开发中会用到大量的父子组件传值,也会用到动态组件的传值,常规子组件获取父组件的传值时,第一次是获取不到的,这时候有两种解决方案 第一种: 父组件向子组件传的是一个json对象,ES6的方法O ...
- [JZOJ5060] 公路建设
题目描述 在Byteland一共有n个城市,编号依次为1到n,它们之间计划修建m条双向道路,其中修建第i条道路的费用为ci. Byteasar作为Byteland公路建设项目的总工程师,他决定选定一个 ...