POJ3723

http://poj.org/problem?id=3723

题意

windy要组建一支军队,召集了N个女孩和M个男孩,每个人要付10000RMB,但是如果一个女孩和一个男孩有关系d的,且已经付给了其中一个人的钱,那么就可以付给另一个人10000-d元,求windy最少要付多少钱。

思路

题目所给的数据是两两之间的连通关系,比较适合用kruskal+并查集求解。

但这个题要求的是最大生成树,不是最小生成树哦,需要修改比较条件。当然将d取反再求最小生成树也是一样的。

代码

Source Code

Problem: 3723       User: liangrx06
Memory: 996K Time: 360MS
Language: C++ Result: Accepted
Source Code
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std; const int N = 20000;
const int R = 50000; struct Node {
int x, y, d;
}; int n, r;
Node node[R+1];
int pre[N+1];
int rank[N+1]; bool cmp(const Node& a, const Node& b)
{
return a.d < b.d;
} void init()
{
for (int i = 1; i <= n; i ++) {
pre[i] = i;
rank[i] = 0;
}
} int find(int a)
{
while (a != pre[a])
a = pre[a];
return a;
} void unite(int a, int b)
{
a = find(a);
b = find(b);
if (a == b) return;
if (rank[a] < rank[b]) {
pre[a] = b;
} else {
pre[b] = a;
if (rank[a] == rank[b])
rank[a] ++;
}
} bool same(int a, int b)
{
return find(a) == find(b);
} int kruskal()
{
sort(node+1, node+r+1, cmp);
int res = 0;
for (int i = 1; i <= r; i ++) {
int x = node[i].x, y = node[i].y;
if (!same(x, y)) {
unite(x, y);
res += node[i].d;
}
}
return res;
} int main(void)
{
int t, n1, n2;
cin >> t;
while (t--) {
cin >> n1 >> n2 >> r;
n = n1 + n2;
int x, y, d;
for (int i = 1; i <= r; i ++) {
scanf("%d%d%d", &x, &y, &d);
node[i].x = x + 1;
node[i].y = n1 + y + 1;
node[i].d = -d;
}
init();
printf("%d\n", 10000 * n + kruskal());
} return 0;
}

POJ3169

POJ1258

http://poj.org/problem?id=1258

题意

有n个农场,已知这n个农场都互相相通,有一定的距离,现在每个农场需要装光纤,问怎么安装光纤能将所有农场都连通起来,并且要使光纤距离最小,输出安装光纤的总距离。

思路

求最小生成树,由于这个题直接给出了邻接矩阵,所以用prim算法比较合适。

代码

Source Code

Problem: 1258       User: liangrx06
Memory: 212K Time: 16MS
Language: C++ Result: Accepted
Source Code
#include <iostream>
#include <cstdio>
using namespace std; const int N = 100;
const int INF = 0x3f3f3f3f; int n;
int d[N][N];
int md[N];
bool used[N]; int prim()
{
fill(md, md+n, INF);
fill(used, used+n, false);
md[0] = 0;
int res = 0;
while (true) {
int v = -1;
for (int i = 0; i < n; i ++) {
if (!used[i] && (v == -1 || md[i] < md[v]))
v = i;
}
if (v == -1) break;
used[v] = true;
res += md[v];
for (int i = 0; i < n; i ++) {
md[i] = min(md[i], d[v][i]);
}
}
return res;
} int main(void)
{
while (scanf("%d", &n) != EOF) {
for (int i = 0; i < n; i ++) {
for (int j = 0; j < n; j ++) {
scanf("%d", &d[i][j]);
}
}
printf("%d\n", prim());
} return 0;
}

POJ2377

http://poj.org/problem?id=2377

题意

给定一些两点之间的连通距离,求最大生成树。

思路

题目所给的数据是两两之间的连通关系,比较适合用kruskal+并查集求解。

但这个题要求的是最大生成树,排序的时候按降序排列或者将距离取反最后结果再取反就可以了。

代码

Source Code

Problem: 2377       User: liangrx06
Memory: 496K Time: 32MS
Language: C++ Result: Accepted
Source Code
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std; const int N = 1000;
const int M = 20000; struct Node {
int x, y, d;
}; int n, m;
Node node[M+1];
int pre[N+1];
int rank[N+1]; bool cmp(const Node& a, const Node& b)
{
return a.d < b.d;
} void init()
{
for (int i = 1; i <= n; i ++) {
pre[i] = i;
rank[i] = 0;
}
} int find(int a)
{
while (a != pre[a])
a = pre[a];
return a;
} void unite(int a, int b)
{
a = find(a);
b = find(b);
if (a == b) return;
if (rank[a] < rank[b]) {
pre[a] = b;
} else {
pre[b] = a;
if (rank[a] == rank[b])
rank[a] ++;
}
} bool same(int a, int b)
{
return find(a) == find(b);
} int kruskal()
{
sort(node+1, node+m+1, cmp);
int res = 0;
int uniteTime = 0;
for (int i = 1; i <= m; i ++) {
int x = node[i].x, y = node[i].y;
if (!same(x, y)) {
unite(x, y);
uniteTime ++;
res += node[i].d;
}
}
if (uniteTime == n-1)
return -res;
else
return -1;
} int main(void)
{
cin >> n >> m;
for (int i = 1; i <= m; i ++) {
scanf("%d%d%d", &node[i].x, &node[i].y, &node[i].d);
node[i].d *= -1;
}
init();
printf("%d\n", kruskal()); return 0;
}

POJ2395

http://poj.org/problem?id=2395

题意

有N个农场,它们是连通的,现在你要从1号农场找到路走到其他所有农场去。但是有个要求就是你必须使得你将要走的单段路的最大长度最小。也就是说,任意两个农场之间的路如果被你选中要走的话,那么这种单段路的最大值必须尽量小。

思路

其实就是要你选一些路使得所有农场属于同一个连通分量,且要求你输出最大边的值. 仔细想想kruskal算法,它从所有边长从小到大的顺序开始选边,每次选边都使得两个点连通. 可以证明kruskal算法所选择的最后一条边即是我们本题的答案.

最小瓶颈生成树在刘汝佳<<训练指南>>P343页有详细的介绍.

无向图G的一颗瓶颈生成树(bottleneck spanning tree)T是这样的一颗生成树,它最大的边权值在G的所有生成树中是最小的。

无向图的最小生成树一定是瓶颈生成树,但瓶颈生成树不一定是最小生成树。(来自百度百科:瓶颈生成树)

代码

Source Code

Problem: 2395       User: liangrx06
Memory: 388K Time: 79MS
Language: C++ Result: Accepted
Source Code
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std; const int N = 2000;
const int M = 10000; struct Node {
int x, y, d;
}; int n, m;
Node node[M+1];
int pre[N+1];
int rank[N+1]; bool cmp(const Node& a, const Node& b)
{
return a.d < b.d;
} void init()
{
for (int i = 1; i <= n; i ++) {
pre[i] = i;
rank[i] = 0;
}
} int find(int a)
{
while (a != pre[a])
a = pre[a];
return a;
} void unite(int a, int b)
{
a = find(a);
b = find(b);
if (a == b) return;
if (rank[a] < rank[b]) {
pre[a] = b;
} else {
pre[b] = a;
if (rank[a] == rank[b])
rank[a] ++;
}
} bool same(int a, int b)
{
return find(a) == find(b);
} int kruskal()
{
sort(node+1, node+m+1, cmp);
int res = 0;
int uniteTime = 0;
for (int i = 1; i <= m; i ++) {
int x = node[i].x, y = node[i].y;
if (!same(x, y)) {
unite(x, y);
uniteTime ++;
res = node[i].d;
}
}
if (uniteTime == n-1)
return res;
else
return -1;
} int main(void)
{
cin >> n >> m;
for (int i = 1; i <= m; i ++) {
scanf("%d%d%d", &node[i].x, &node[i].y, &node[i].d);
}
init();
printf("%d\n", kruskal()); return 0;
}

AOJ2224

http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=2224

题意

有N个木桩M个栅栏,栅栏连接木桩,现在这些栅栏围成的封闭空间里有至少一只猫,要求破环若干个栅栏救出猫,问破环栅栏的最小长度。

思路

题目要求栅栏不组成圈,又要求破坏栅栏的最小长度,那么剩下的栅栏自然是最大生成树了(当然前提是图是连通的)。kruskal+并查集求最大生成树,在从大到小添加边的过程中,如果发现新添加的边的两个节点已经连通,说明这个边需要去掉,累加这个边的长度到结果变量res。
另外,即使这个图非连通,这样的破圈求解过程仍然能够得到正确答案。

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std; const int N = 10000;
const int M = 10000*10000/2; struct Node {
int x, y;
double d;
}; int n, m;
Node node[M+1];
int pre[N+1];
int rank[N+1]; bool cmp(const Node& a, const Node& b)
{
return a.d > b.d;
} void init()
{
for (int i = 1; i <= n; i ++) {
pre[i] = i;
rank[i] = 0;
}
} int find(int a)
{
while (a != pre[a])
a = pre[a];
return a;
}
void unite(int a, int b)
{
a = find(a);
b = find(b);
if (a == b) return;
if (rank[a] < rank[b]) {
pre[a] = b;
} else {
pre[b] = a;
if (rank[a] == rank[b])
rank[a] ++;
}
} bool same(int a, int b)
{
return find(a) == find(b);
} double distance(int x1, int y1, int x2, int y2)
{
return sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2));
} double kruskal()
{
sort(node+1, node+m+1, cmp);
double res = 0;
for (int i = 1; i <= m; i ++) {
int x = node[i].x, y = node[i].y;
if (!same(x, y))
unite(x, y);
else
res += node[i].d;
}
return res;
} int main(void)
{
int a[N+1], b[N+1];
cin >> n >> m;
for (int i = 1; i <= n; i ++) {
scanf("%d%d", &a[i], &b[i]);
}
for (int i = 1; i <= m; i ++) {
scanf("%d%d", &node[i].x, &node[i].y);
int x = node[i].x, y = node[i].y;
node[i].d = distance(a[x], b[x], a[y], b[y]);
}
init();
printf("%.3lf\n", kruskal()); return 0;
}

《挑战程序设计竞赛》2.5 最小生成树 POJ3723 3169 1258 2377 2395 AOJ2224(1)的更多相关文章

  1. Aizu 2249Road Construction 单源最短路变形《挑战程序设计竞赛》模板题

    King Mercer is the king of ACM kingdom. There are one capital and some cities in his kingdom. Amazin ...

  2. 《挑战程序设计竞赛》2.3 动态规划-优化递推 POJ1742 3046 3181

    POJ1742 http://poj.org/problem?id=1742 题意 有n种面额的硬币,面额个数分别为Ai.Ci,求最多能搭配出几种不超过m的金额? 思路 据说这是传说中的男人8题呢,对 ...

  3. 挑战程序设计竞赛》P345 观看计划

                                                 <挑战程序设计竞赛>P345 观看计划 题意:一周一共有M个单位的时间.一共有N部动画在每周si时 ...

  4. POJ 2386 Lake Counting 题解《挑战程序设计竞赛》

    地址 http://poj.org/problem?id=2386 <挑战程序设计竞赛>习题 题目描述Description Due to recent rains, water has ...

  5. poj 3253 Fence Repair 贪心 最小堆 题解《挑战程序设计竞赛》

    地址 http://poj.org/problem?id=3253 题解 本题是<挑战程序设计>一书的例题 根据树中描述 所有切割的代价 可以形成一颗二叉树 而最后的代价总和是与子节点和深 ...

  6. 《挑战程序设计竞赛》 4.1.1 矩阵 P286

    想写几篇挑战的感悟,也有助于自己理解这本书.但这上面大多贴的是书上的代码,主要是为了用的时候后直接复制就好了,这样就很方便了,就相当于黑盒模板了. 1.线性方程组 /** \brief 高斯消元法 * ...

  7. poj1182食物链_并查集_挑战程序设计竞赛例题

    食物链 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 65534   Accepted: 19321 Description ...

  8. 迷宫问题_BFS_挑战程序设计竞赛p34

    给定一个N*M的迷宫,求从起点到终点的最小步数. N,M<100: 输入: 10 10#S######.#......#..#.#.##.##.#.#........##.##.####.... ...

  9. 【网络流#9】POJ 2135 Farm Tour 最小费用流 - 《挑战程序设计竞赛》例题

    [题意]给出一张无向图,从1开始到n,求两条没有公共边的最短路,使得路程总和最小 每条边的权值设为费用,最大流量设为1,然后就是从源点到汇点流量为2的最小费用流. 因为是规定了流量,新建一个源点和一个 ...

随机推荐

  1. VS2010 快捷键设置,快速编码1

    全屏:Shift+Alt+Enter注释选定内容:Ctrl+E+C/Crtr+E+U代码格式化:ctrl+E+F VS2008 使用小技巧——快捷键1. 怎样调整代码排版的格式?选择:编辑—>高 ...

  2. Unity中坐标系转换方法

    前言 本篇文章主要是参考<Unity API 解析>---陈泉宏. 这是本人在学校图书馆找到一本书,主要介绍的就是常用的类,比较实用,没有冗余的地方.在此推荐一下这本书! 一.Screen ...

  3. IOS 命令行编译

    转自:简书 IOS 命令行编译   发表于 IOS2013-08-17 07:07 字数: 583 阅读量: 61 This document will note about the ios comm ...

  4. 将Excel中读取的科学计数法表示的Double数据转换为对应的字符串

    已在SegmentFault提问,目前没有答案,自行实现如下: private static String getRealNumOfScientificNotation(String doubleSt ...

  5. URAL 1203 Scientific Conference(贪心 || DP)

    Scientific Conference 之前一直在刷计算几何,邀请赛连计算几何的毛都买见着,暑假这一段时间就做多校.补多校的题目.刷一下一直薄弱的DP.多校假设有计算几何一定要干掉-.- 题意:给 ...

  6. Mac普通用户修改了/etc/sudoers文件的解决办法

    1.开启 Root 账户 打开“系统偏好设置”,进入“用户与群组”面板,记得把面板左下角的小锁打开,然后选择面板里的“登录选项”.在面板右边你会看到“网络账户服务 器”,点击它旁边的“加入…”按钮,再 ...

  7. m2014-architecture-webserver->百万记录级mysql数据库及Discuz!论坛优化

    作者:shunz,出处:http://shunz.net/2008/06/mysql_discuz_.html 最近,帮一个朋友优化一个拥有20万主题,100万帖子,3万多会员,平均在线人数2000人 ...

  8. PHP5 session 详解【经典】

    原文:http://www.pkwind.com/php5-session-xiang-jie-jing-dian http协议是WEB服务器与客户端 (浏览器)相互通信的协议,它是一种无状态协议.所 ...

  9. 改进动态设置query cache导致额外锁开销的问题分析及解决方法-mysql 5.5 以上版本

    改进动态设置query cache导致额外锁开销的问题分析及解决方法 关键字:dynamic switch for query cache,  lock overhead for query cach ...

  10. 为什么setinterval和settimeout越点击越快以及响应的解决办法

    setinterval大家都很了解,但是如果时间长的话,误差也会越来越大,所以我习惯上使用settimeout的递归,闲来没事,写了一个定时器的递归 <!DOCTYPE html> < ...