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. e648. 双击和三击事件

    component.addMouseListener(new MyMouseListener()); public class MyMouseListener extends MouseAdapter ...

  2. 【转载】WebApi 接口测试工具:WebApiTestClient

    正文 前言:这两天在整WebApi的服务,由于调用方是Android客户端,Android开发人员也不懂C#语法,API里面的接口也不能直接给他们看,没办法,只有整个详细一点的文档呗.由于接口个数有点 ...

  3. 云计算中auto-scaling 最早的来源

    什么是弹性?首先,整合计算资源,将计算资源池化,通过虚拟机按需使用计算资源;其次,按量计费,让用户能够根据使用量按月按时甚至按秒来进行付费. 不过,光有了这两条还不够.为什么?我举个例子: 很多做运维 ...

  4. 建造者模式(build pattern)-------创造型模式

    将一个复杂对象的构建与它的标示分离,使得同样的构建过程可以创建不同的标示. 建造者模式是较为复杂的创建型模式,它将客户端与包含多个组成部分(或部件)的复杂对象的创建过程分离,客户端无须知道复杂对象的内 ...

  5. Linux下的CPU性能瓶颈分析案例

    问题描述: 在对notify执行性能测试时发现cpu负载突然飙高,cpu利用率高达95%.这时候就要排查是哪些线程消耗了cpu,并从代码层找到占用cpu的“罪魁祸首”. 步骤: 1. 先用ps+gre ...

  6. Linux /proc/loadavg(平均负载)

    from : http://hi.baidu.com/mengyun8/blog/item/bd424531451b98e71a4cffc0.html 一.什么是系统平均负载(Load average ...

  7. 解决IE6双倍边距BUG

    解决IE6双倍边距BUG,只要满足下面3个条件才会出现这个BUG: 1)要为块状元素; 2)要左侧浮动; 3)要有左外边距(margin-left); 解决这个BUG很容易,只需要在相应的块状元素的C ...

  8. Apache Commons工具集简介

  9. laravel 使用验证码

    1)php.ini需要开两个扩展 extension=php_fileinfo.dllextension=php_gd2.dll 2)使用composer安装类包 composer require m ...

  10. 多线程模块:thread

    thread 常见用法如下: thread.start_new_thread(function, args):用于开启一个新的线程,接收两个参数,分别为函数和该函数的参数,相当于开启一个新的线程来执行 ...