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. linux -- Ubuntu 安装搜狗输入法

    在Ubuntu Kylin系统中,默认安装搜狗拼音输入法,但是在原生Ubuntu系统中则不是.这可以理解,毕竟搜狗输入法的Linux版有Kylin团队的不小功劳.由于搜狗输入法确实比Linux系统下其 ...

  2. Java基础-JDBC访问数据库

    基本步骤: 加载数据库驱动 建立连接 创建SQL语句 执行SQL语句 处理执行结果 释放资源 代码示例: import java.sql.Connection; import java.sql.Dri ...

  3. fstrict-aliasing

    承如“optimization blocks”文中所述,由于相同的指针可能指向相关的内存区,因此编译器将不做过分的优化…… 特意搜了下编译器在不同的优化等级下都有哪些默认优化,因此有了此记录(比较长, ...

  4. win10系统下cmd输入一下安装的软件命令提示拒绝访问解决办法

    问题:win10系统安装了nvm,cmd命令提示不是内部或外部命令 解决:卸载nvm,重新安装,再一次输入nvm,发现正常显示: 问题:win10安装了nvm之后,安装node成功,输入node命令, ...

  5. WPF: 把引用的dll移动到自定义路径

    需求: 有A.exe和B.exe, 都引用了 C.dll, output路径都是 W:\Debug. A和B都添加了对C的引用,正常情况下C会被复制到 output 里面. C这样子的dll很多,不想 ...

  6. ubuntu 执行make menuconfig ARCH=arm

    1.ubuntu 执行make menuconfig ARCH=arm出错了!! *** Unable to find the ncurses libraries or the *** require ...

  7. [ACM] poj 2017 Speed Limit

    Speed Limit Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 17030   Accepted: 11950 Des ...

  8. 用rman恢复备库;遇到备库起不来一个案例 ORA-01152:ORA-01110

    数据从主库恢复到备库:打开备库发现出现异常 SQL> alter database open; alter database open * ERROR at line 1: ORA-10458: ...

  9. YARN应用程序开发和设计流程

    从业务的角度看,一个应用需要分两部分进行开发,一个是接入YARN平台,实现3个协议,通过YARN实现对集群资源的访问和利用:另一个是业务功能的实现,这个与YARN本身没有太大关系.下面主要阐述如何将一 ...

  10. CentOS5.5环境下布署LVS+keepalived

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://kerry.blog.51cto.com/172631/401253 #!/bin ...