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. EF中修改对象的值的问题。。。(字段超级多的时候)

    一般EF中修改单个对象的值,我是这样处理的. 如:DBEntities db=new DBEntities(); student stu = db.student.firstOrdefault(m=& ...

  2. 【LeetCode】Validate Binary Search Tree 二叉查找树的推断

    题目: Given a binary tree, determine if it is a valid binary search tree (BST). 知识点:BST的特点: 1.一个节点的左子树 ...

  3. Powershell 的自己主动部署

     工作中反复性的版本号移植,一天上线10几次,让我痛不欲生,频繁的操作也可能出现疲劳性失误,导致严重的生产故障.于是乎,闲暇时间.我開始研究使用powershell自己主动部署程序到Linuxse ...

  4. 关于write solid code中的memset

    文中说明memset可以通过操作整形以加速程序执行速度,这一点值得肯定,问题在于unicore或arm中协处理器有地址访问对齐检查,如果我们如此操作,编译器最终使用str指令来完成,那么当地址未对齐时 ...

  5. [转] web_reg_save_param得到的数组的处理

    方法一: 函数(sprintf,web_reg_save_param),其中红色字体是本文档最重要的#include "web_api.h" Action(){int i,iloo ...

  6. CSS之少用继承,多用组合

    下面是一段普通的代码: css: .box{ border:1px solid #ccc; font-size:12px; background:#f1f1f1; padding:10px; } ht ...

  7. 扩展方法和Lambda之练习手记

    扩展方法是我们日常开发当中所经常简化代码,提高性能和代码可读性的一个重要开发手段. 扩展方法是一个只能在静态类中声明的静态方法 Lambda 是一个表达式 ,学会了 可以使代码简洁,也是装13的利器. ...

  8. tiny6410SDK制作NFS文件系统

    1.初次编译内核出现问题 解决方法:将uboot的tools目录 下的mkimage拷贝到/bin/下. 2.开机后终端出现mmc0: error -110 whilst initialising S ...

  9. linq select

    var categoryIdArray = MusicCategoryRelationBLL.GetModel(music.Id); music.MusicCategoryIds = string.E ...

  10. java.lang.IncompatibleClassChangeError: Implementing class

    项目中使用了quartz,但是jar包却有两个,一个1.8版本,一个2.1版本,导致jar包冲突,所以导致一启动tomcat就出现: Caused by: java.lang.Incompatible ...