UVA 1151 - Buy or Build(最小生成树,二进制子集生成)

2023-12-05 02:09

本文主要是介绍UVA 1151 - Buy or Build(最小生成树,二进制子集生成),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

自己实力有限。 在为了K神之后。 自己才写出来的。  二进制子集生成 又忘记了。 又去 前面翻书看的。 (P 190)


这个题。  首先要去生成 最小生成树(也就是 不同套餐的情况)  


然后 用二进制子集生成。 枚举 所有套餐的选择情况。比如 套餐有 1 2 3  三种套餐 则 需要求出 所有可能的组合。 1 , 1 2, 1 3, 1 2 3,


这样 选择每一个子集 对于每一个子集 所形成的 联通分量用并查集保存。  在 子集之外。 肯定有一些点没有链接上。


那么下一步就是 用最小生成树 把 联通分量之外的点连上(因为这样连才能保证 连上的费用是最小的)


二进制枚举子集的方法


#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <string>
#include <map>
#include <vector>
#include <set>
#include <queue>
#include <stack>
#include <cctype>
using namespace std;
#define ll long long
typedef unsigned long long ull;
#define maxn 2000000+10
#define INF 1<<30
int main (){
    //0 1 2 3 4  的子集生成for(int i = 0; i < (1 << 5) ; i++){for(int j = 0; j < 5; j++){if(i&(1 << j))printf("%d ",j);}printf("\n");}return 0;
}


代码中都有注释


#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <string>
#include <map>
#include <vector>
#include <set>
#include <queue>
#include <stack>
#include <cctype>
using namespace std;
#define ll long long
typedef unsigned long long ull;
#define maxn 1000+10
#define INF 1<<30
struct po{int x,y;
};
struct point{int u, v;int cost;friend bool operator <(point a, point b){return a.cost < b.cost;}
};
po s[maxn];
int fa[maxn];    // 并查集父节点
vector <point> r;   // 所有的点到点的边的长度
vector <int> l;   //  这是最小生成树中的边。
vector <int> q[maxn]; // 保存的是 所有的套餐情况 其中q[i][0] 为这个套餐的费用 后面的都是套餐的点
int n,counts;   // n为点数  counts 为 套餐数
int find_fa(int x){return fa[x] == x ? x : fa[x] = find_fa(fa[x]);}
int init_fa(){for(int i = 0; i <= n; i++)fa[i] = i;
}
int line(int i,int j){return (s[i].x - s[j].x)*(s[i].x - s[j].x) + (s[i].y - s[j].y)*(s[i].y - s[j].y);
}
int solve(int s){init_fa();int cost = 0;int num = 0; // 边数for(int i = 0; i < counts; i++){   // 二进制子集生成 选择可能的套餐情况 收入并查集if(s&(1 << i)){cost += q[i][0];for(int j = 2; j < q[i].size() ; j++){int x = find_fa(q[i][j]);int y = find_fa(q[i][j-1]);if(x != y){fa[y] = x;num ++;}}}}for(int i = 0; num < n - 1; i++){ // 在所生成的子集中。 按照最小生成树 补边int l_ = l[i];int x = find_fa(r[l_].u);int y = find_fa(r[l_].v);int c = r[l_].cost;if(x != y){cost += c;num++;fa[x] = y;}}return cost;
}
int main (){int num;int b = 0;scanf("%d",&num);while(num--){if(b)printf("\n");b++;scanf("%d%d",&n,&counts);r.clear();l.clear();for(int i = 0; i <= counts; i++)q[i].clear();for(int i = 0; i < counts; i++){int x;scanf("%d",&x);int mo;for(int j = 0; j <= x; j++){scanf("%d",&mo);q[i].push_back(mo);  // q 第一项代表 费用。 后面代表点。}}for(int i = 1; i <= n; i++)scanf("%d%d",&s[i].x,&s[i].y);init_fa();for(int i = 1; i <= n-1; i++){for(int j = i+1; j <= n; j++){point pp;pp.u = i,pp.v = j,pp.cost = line(i,j);r.push_back(pp);// printf("%d %d %d\n",i,j,line(i,j));}}sort(r.begin(),r.end());int len = r.size();int minn = 0;for(int i = 0; i < len; i++){ // 并查集形成 最小生成树的 集合int uu = r[i].u;int vv = r[i].v;int x = find_fa(uu);int y = find_fa(vv);if(x != y){fa[x] = y;minn += r[i].cost;l.push_back(i); // 求出 最小生成树的边的集合}}int cost_min = minn;   //  没有套餐的时候for(int i = 1; i < (1 << counts); i++){  // 枚举选择 所有套餐的子集int minx = solve(i);cost_min = min(minx, cost_min);}printf("%d\n",cost_min);}return 0;
}




这篇关于UVA 1151 - Buy or Build(最小生成树,二进制子集生成)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/455728

相关文章

AI一键生成 PPT

AI一键生成 PPT 操作步骤 作为一名打工人,是不是经常需要制作各种PPT来分享我的生活和想法。但是,你们知道,有时候灵感来了,时间却不够用了!😩直到我发现了Kimi AI——一个能够自动生成PPT的神奇助手!🌟 什么是Kimi? 一款月之暗面科技有限公司开发的AI办公工具,帮助用户快速生成高质量的演示文稿。 无论你是职场人士、学生还是教师,Kimi都能够为你的办公文

pdfmake生成pdf的使用

实际项目中有时会有根据填写的表单数据或者其他格式的数据,将数据自动填充到pdf文件中根据固定模板生成pdf文件的需求 文章目录 利用pdfmake生成pdf文件1.下载安装pdfmake第三方包2.封装生成pdf文件的共用配置3.生成pdf文件的文件模板内容4.调用方法生成pdf 利用pdfmake生成pdf文件 1.下载安装pdfmake第三方包 npm i pdfma

uva 10055 uva 10071 uva 10300(水题两三道)

情歌两三首,水题两三道。 好久没敲代码了为暑假大作战热热身。 uva 10055 Hashmat the Brave Warrior 求俩数相减。 两个debug的地方,一个是longlong,一个是输入顺序。 代码: #include<stdio.h>int main(){long long a, b;//debugwhile(scanf("%lld%lld", &

poj 3259 uva 558 Wormholes(bellman最短路负权回路判断)

poj 3259: 题意:John的农场里n块地,m条路连接两块地,w个虫洞,虫洞是一条单向路,不但会把你传送到目的地,而且时间会倒退Ts。 任务是求你会不会在从某块地出发后又回来,看到了离开之前的自己。 判断树中是否存在负权回路就ok了。 bellman代码: #include<stdio.h>const int MaxN = 501;//农场数const int

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

poj 1287 Networking(prim or kruscal最小生成树)

题意给你点与点间距离,求最小生成树。 注意点是,两点之间可能有不同的路,输入的时候选择最小的,和之前有道最短路WA的题目类似。 prim代码: #include<stdio.h>const int MaxN = 51;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int P;int prim(){bool vis[MaxN];

poj 2349 Arctic Network uva 10369(prim or kruscal最小生成树)

题目很麻烦,因为不熟悉最小生成树的算法调试了好久。 感觉网上的题目解释都没说得很清楚,不适合新手。自己写一个。 题意:给你点的坐标,然后两点间可以有两种方式来通信:第一种是卫星通信,第二种是无线电通信。 卫星通信:任何两个有卫星频道的点间都可以直接建立连接,与点间的距离无关; 无线电通信:两个点之间的距离不能超过D,无线电收发器的功率越大,D越大,越昂贵。 计算无线电收发器D

uva 10387 Billiard(简单几何)

题意是一个球从矩形的中点出发,告诉你小球与矩形两条边的碰撞次数与小球回到原点的时间,求小球出发时的角度和小球的速度。 简单的几何问题,小球每与竖边碰撞一次,向右扩展一个相同的矩形;每与横边碰撞一次,向上扩展一个相同的矩形。 可以发现,扩展矩形的路径和在当前矩形中的每一段路径相同,当小球回到出发点时,一条直线的路径刚好经过最后一个扩展矩形的中心点。 最后扩展的路径和横边竖边恰好组成一个直

uva 10061 How many zero's and how many digits ?(不同进制阶乘末尾几个0)+poj 1401

题意是求在base进制下的 n!的结果有几位数,末尾有几个0。 想起刚开始的时候做的一道10进制下的n阶乘末尾有几个零,以及之前有做过的一道n阶乘的位数。 当时都是在10进制下的。 10进制下的做法是: 1. n阶位数:直接 lg(n!)就是得数的位数。 2. n阶末尾0的个数:由于2 * 5 将会在得数中以0的形式存在,所以计算2或者计算5,由于因子中出现5必然出现2,所以直接一

uva 568 Just the Facts(n!打表递推)

题意是求n!的末尾第一个不为0的数字。 不用大数,特别的处理。 代码: #include <stdio.h>const int maxn = 10000 + 1;int f[maxn];int main(){#ifdef LOCALfreopen("in.txt", "r", stdin);#endif // LOCALf[0] = 1;for (int i = 1; i <=