继续畅通工程
2015-07-27 20:06
369 查看
[align=left]Problem Description[/align]
省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建道路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全省畅通需要的最低成本。
[align=left]Input[/align]
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( 1< N < 100 );随后的 N(N-1)/2 行对应村庄间道路的成本及修建状态,每行给4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态:1表示已建,0表示未建。
当N为0时输入结束。
[align=left]Output[/align]
每个测试用例的输出占一行,输出全省畅通需要的最低成本。
[align=left]Sample Input[/align]
3
1 2 1 0
1 3 2 0
2 3 4 0
3
1 2 1 0
1 3 2 0
2 3 4 1
3
1 2 1 0
1 3 2 1
2 3 4 1
0
[align=left]Sample Output[/align]
3
1
0
[align=left]题解:最小生成树3种做法。把存在的费用设置为0就解决了存在的公路问题。因为如果存在的公路是最小生成树的边,那么我就+0,。[/align]
[align=left]
[/align]
[align=left]
[/align]
普里姆:
[align=left]
[/align]
克鲁斯卡尔:
省政府“畅通工程”的目标是使全省任何两个村庄间都可以实现公路交通(但不一定有直接的公路相连,只要能间接通过公路可达即可)。现得到城镇道路统计表,表中列出了任意两城镇间修建道路的费用,以及该道路是否已经修通的状态。现请你编写程序,计算出全省畅通需要的最低成本。
[align=left]Input[/align]
测试输入包含若干测试用例。每个测试用例的第1行给出村庄数目N ( 1< N < 100 );随后的 N(N-1)/2 行对应村庄间道路的成本及修建状态,每行给4个正整数,分别是两个村庄的编号(从1编号到N),此两村庄间道路的成本,以及修建状态:1表示已建,0表示未建。
当N为0时输入结束。
[align=left]Output[/align]
每个测试用例的输出占一行,输出全省畅通需要的最低成本。
[align=left]Sample Input[/align]
3
1 2 1 0
1 3 2 0
2 3 4 0
3
1 2 1 0
1 3 2 0
2 3 4 1
3
1 2 1 0
1 3 2 1
2 3 4 1
0
[align=left]Sample Output[/align]
3
1
0
[align=left]题解:最小生成树3种做法。把存在的费用设置为0就解决了存在的公路问题。因为如果存在的公路是最小生成树的边,那么我就+0,。[/align]
[align=left]
[/align]
普里姆优化做法:
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <vector> using namespace std; //327ms ,vector耗时间 const int INF = 105; struct Node { int to; int cost; Node(){} Node(int a,int b) { to = a; cost = b; } bool operator< (Node t) const { return cost > t.cost; } }; priority_queue<Node> q; vector<Node> vec[INF]; bool visited[INF]; int ans; void prim(int n) { memset(visited,false,sizeof(visited)); ans = 0; for(int i = 0;i < vec[1].size();i++) //从1开始 { q.push(vec[1][i]); } visited[1] = true; int cnt = 0; while(!q.empty() && cnt < n -1) //找到n-1条边 { Node t = q.top(); q.pop(); if(visited[t.to]) //访问过 { continue; } ans += t.cost; visited[t.to] = true; cnt++; for(int i = 0;i < vec[t.to].size();i++) //更新队列 { if(!visited[vec[t.to][i].to]) { q.push(vec[t.to][i]); } } } printf("%d\n",ans); for(int i = 1;i <= n;i++) { vec[i].clear(); } while(!q.empty()) { q.pop(); } } int main() { int n; int u,v,c,s; while(scanf("%d",&n) && n != 0) { for(int i = 0;i < n * (n - 1) / 2;i++) { scanf("%d%d%d%d",&u,&v,&c,&s); if(0 == s) { vec[u].push_back(Node(v,c)); vec[v].push_back(Node(u,c)); } else { vec[u].push_back(Node(v,0)); vec[v].push_back(Node(u,0)); } } prim(n); } return 0; }
[align=left]
[/align]
普里姆:
#include <iostream> #include <cstdio> #include <cstring> #include <vector> using namespace std; //运行时间327ms const int INF = 0x3fffffff; int map[101][105]; bool visited[105]; int e[105]; int ans; void prim(int n) { memset(visited,false,sizeof(visited)); ans = 0; for(int i = 1;i <= n;i++) { e[i] = map[1][i]; //从1开始找 } e[1] = 0; visited[1] = true; for(int i = 1;i < n;i++) //找n-1条边 { int min = INF; int k; for(int j = 1;j <= n;j++) { if(!visited[j] && min > e[j]) //找到最小边 { min = e[j]; k = j; } } ans += min; //找到了一条 visited[k] = true; for(int j = 1;j <= n;j++) //更新数组最小值 { if(!visited[j] && e[j] > map[k][j]) { e[j] = map[k][j]; } } } printf("%d\n",ans); } int main() { int n; int u,v,c,s; while(scanf("%d",&n) && n != 0) { for(int i = 0;i < n * (n - 1) / 2;i++) { scanf("%d%d%d%d",&u,&v,&c,&s); if(0 == s) { map[u][v] = c; map[v][u] = c; } else { map[u][v] = 0; //表示不需要花费钱了 map[v][u] = 0; } } prim(n); } return 0; }
[align=left]
[/align]
克鲁斯卡尔:
#include <iostream> #include <cstring> #include <cstdio> #include <vector> #include <algorithm> using namespace std; //运行时间493ms struct Node { int u; int v; int cost; Node(){} Node(int a,int b,int c) { u = a; v = b; cost = c; } bool operator< (Node t) const { return cost < t.cost; } }; Node e[10005]; bool visited[105]; int fa[105]; int ans; int find(int x) //并查集 { if(x == fa[x]) { return x; } return fa[x] = find(fa[x]); } void kruskal(int n) { sort(e,e + n * (n - 1) / 2); //排序后找最小边 int k = 0; for(int i = 1;i < n;i++) //n-1条边 { for(int j = k;j < n * (n - 1) / 2;j++) { int x = find(e[j].u); int y = find(e[j].v); if(x == y) //判断是不是同一个集合 { continue; } fa[x] = y; //加入同一个集合 visited[e[j].u] = true; visited[e[j].v] = true; ans += e[j].cost; k = j + 1; break; } } printf("%d\n",ans); } int main() { int n; int u,v,c,s; while(scanf("%d",&n) && n != 0) { ans = 0; int k = 0; for(int i = 0;i < n * (n - 1) / 2;i++) { scanf("%d%d%d%d",&u,&v,&c,&s); if(0 == s) { e[k++] = Node(u,v,c); } else { e[k++] = Node(u,v,0); //0表示修建了该路,所以不需要成本 } } for(int i = 1;i <= n;i++) { fa[i] = i; } memset(visited,false,sizeof(visited)); kruskal(n); } return 0; }
相关文章推荐
- 多态与继承中的开闭原则和里氏替换原则简述
- Android之——手机黑名单的实现
- SPI理解
- CFI与SPI flash区别
- C#编程:字符串转16进制数据以及16进制数据转字符串
- PL/SQL Developer 和 instantclient客户端安装配置
- Arctic Network---poj2349 最小生成树
- 深入理解JAVA虚拟机笔记-05
- NoSql——mongoDB(副本集)
- TCP学习记录
- Web应用程序开发原理
- Gym 100703M It's complicated 水题
- 【基础练习】【快速幂】codevs3285 转圈游戏题解
- 溢出之后
- uva11059(最大乘积)
- Swift开发教程--如何播放图片动画
- 最近半年工作总结
- NSString中stringWithFormat的用法
- 一起talk C栗子吧(第二十五回:C语言实例--二分查找)
- 第二章 知识图谱——机器大脑中的知识库