【算法每日一练]-图论(保姆级教程篇14 )#会议(模板题) #医院设置 #虫洞 #无序字母对 #旅行计划 #最优贸易

目录

今日知识点:

求数的重心先dfs出d[1]和cnt[i],然后从1进行dp求解所有d[i]

两两点配对的建图方式,检查是否有环

无向图欧拉路径+路径输出

topo+dp求以i为终点的游览城市数

建立分层图转化盈利问题成求最长路

会议(模板题)

医院设置 

虫洞

无序字母对 

旅行计划

最优贸易


        

        

        

会议(模板题)

         

 思路:

补充:首先,阅读题目可以看出来,这道题目实际上就是求树的重心。

树的重心找到一个点,其所有的子树中最大的子树节点数最少,那么这个点就是这棵树的重心,删去重心后,达到的效果是生成的多棵树尽可能平衡。

啊?不是n-1边n点的无向图吗?怎么就一定是棵树了呢?万一是“X”型或者“米”型的无向图呢,哈哈我可太聪明了。

你直接从任意一个点做根开始,然后把该点其余的分支点都掰到下面去。也就是说把其余的子树都扭动到下面去,这不就是一颗树了吗。明白了吗!

OK,怎么解这道题呢?

举个例子:

我们不妨设置d[i]表示以此点为根的所有点总距离和,cnt[i]表示以此为根的节点数

我们首先知道d[1]=16,cnt[1]=10我们来看d[2]应该怎么求,我们发现相对于d[1]来说,如果设2为最佳点,2,5,6其距离-1,剩下的1,4,3,7,8,9,10到其距离+1。

故:d[2]=d[1] - 3 + 7 =20

其中3是子根2对应的节点数cnt[2],7是1为子根对应的节点数cnt[1]-cnt[2]

得:d[i]=d[fa]-cnt[i]+(cnt[1]-cnt[i])

那么只需要先dfs求出来d[1]和每个点的cnt[i]。然后就可以进行dp最终求出所有点的d[i]。

 

#include <bits/stdc++.h>
using namespace std;
const int N=50005;
int minn=0x3f3f3f3f,ans,n,d[N],cnt[N];
vector<int>ve[N];
void dfs(int u,int fa,int len){//一定别走fa回去cnt[u]++;//先加上自己for(int i=0;i<ve[u].size();i++){int v=ve[u][i];if(v==fa)continue;dfs(v,u,len+1);//先求孩子的cnt,之后求自己cntcnt[u]+=cnt[v];}d[1]+=len;//最后求d[1]
}
void dp(int u,int fa){for(int i=0;i<ve[u].size();i++){int v=ve[u][i];if(v==fa)continue;d[v]=d[u]-2*cnt[v]+cnt[1];dp(v,u);//这里对自己进行转移更新,再对孩子的更新}
}
int main(){cin>>n;int a,b;for(int i=1;i<n;i++){cin>>a>>b;ve[a].push_back(b);ve[b].push_back(a);}dfs(1,0,0);dp(1,0);for(int i=1;i<=n;i++){if(d[i]<minn)minn=d[i],ans=i;}cout<<ans<<" "<<minn;
}

上面我打注释的地方一定要理解 

        

        

医院设置 

 

 

思路:

还是一道求树的重心题。不过是每个点都有一个权值。那么把权值当成“另一个世界的节点数”就好了。然后不断求cnt,之后dp就行。 

#include <bits/stdc++.h>
using namespace std;
const int N=500;
int ans=0x3f3f3f3f,n,d[N],cnt[N],w[N];
vector<int>ve[N];
void dfs(int u,int fa,int len){cnt[u]=w[u];//这里还是先加自己for(int i=0;i<ve[u].size();i++){int v=ve[u][i];if(v==fa)continue;dfs(v,u,len+1);cnt[u]+=cnt[v];}d[1]+=len*w[u];//更新d[1]也要变一下
}
void dp(int u,int fa){for(int i=0;i<ve[u].size();i++){int v=ve[u][i];if(v==fa)continue;d[v]=d[u]+cnt[1]-cnt[v]*2;dp(v,u);}ans=min(ans,d[u]);
}
int main(){cin>>n;int c,a,b;for(int i=1;i<=n;i++){cin>>c>>a>>b;w[i]=c;//注意输入方式if(a)ve[i].push_back(a),ve[a].push_back(i);if(b)ve[i].push_back(b),ve[b].push_back(i);}dfs(1,0,0);dp(1,0);cout<<ans;
}

        

        

虫洞

        

思路:
首先分析一下:第一是如何去建图,其次是如何找方案

找方案的话就直接暴力配对吧(题上的数据量不大,肯定要暴力),然后就是建图要保证即要方便图的还原(因为配对后还要回溯呢),又要方便跑图(每次建好都要跑一次看看是否存在一个循环),最后就是坐标范围非常大啊,所以要巧妙一点。

首先:我们对这些黑洞位置排序,只关注同行的,同行中能从A黑洞走到B黑洞的就标记一下A能到B(使用唯一的ID号映射)。

之后:dfs选择配对方案,然后dfs的for函数也是很巧妙:首先要保证不能和前面重复(相当于1号黑洞可以找2,3,4,但是之后4号一定不能再找1,2,3了,所以要保证递增)然后是g[i]=k;g[k]=i这样建图(因为是两两配对,所以每个起点最多只有一个尾点)。最后是建好图后直接从每个黑洞ID号为起点进行查询即可。

最后是检查函数cycle:从起点一直走,走到走过的就可以停止了

#include <bits/stdc++.h>
using namespace std;
int ans,n,to[20],vis[20],g[20];
struct node{int x,y;}p[20];bool cmp(node a,node b){return (a.y<b.y)||(a.y==b.y&&a.x<b.x);
}int cycle(int x){while(to[x]){//走到下一个黑洞,如果有的话if(vis[x])return 1;vis[x]=1;x=g[to[x]];//终点变成起点(如果有的话)}return 0;
}
void dfs(int k){if(k>n){int f=0;for(int i=1;i<=n;i++){//巧妙3:直接从黑洞号开始就行memset(vis,0,sizeof(vis));f|=cycle(i);//巧妙4:这里之所以这么写,是为了防止被标记过1后又被0覆盖掉}ans+=f;return ;}if(g[k])dfs(k+1);else {for(int i=k+1;i<=n;i++){//巧妙1:去重if(g[i])continue;g[i]=k;g[k]=i;//巧妙2:设置两个黑洞的关系dfs(k+1);g[i]=g[k]=0;//清除两个黑洞之间的关系}}
}
int main(){cin>>n;for(int i=1;i<=n;i++)cin>>p[i].x>>p[i].y;sort(p+1,p+1+n,cmp);for(int i=1;i<=n-1;i++){if(p[i].y==p[i+1].y) to[i]=i+1;//把相邻且在同一航 行的标记在一起}dfs(1);cout<<ans;}

首先是方案配对,然后是建图策略(至多两两配对),最后到检查循环都是非常精妙的 ,值得细看

         

        

无序字母对 

思路: 

这里就可以发现实际上就是在找欧拉路,首先每个字符就是代表的图中的某一个点,底下输入的字符串
就代表两点之间有连通,构造字符串就是在找输出一笔画回路,明白这个代码就很简单了

 下面是代码:基于无向图得欧拉路径问题+路径输出

无向图得欧拉路径:连通图,且没有度为奇数的节点(欧拉回路) 或 只有两个2个度为奇数的节点 

#include <bits/stdc++.h>
using namespace std;
const int N=300;
int g[N][N],fa[N],du[N],m;
char ans[N*N],s[N];
int find(int x)
{if(x!=fa[x]) fa[x]=find(fa[x]);return fa[x];//返回祖先 
}void dfs(int x){for(int i=0;i<N;i++)if(g[x][i]){g[x][i]=g[i][x]=0;//取过了这个字母就情空,避免走环 g=0相当于vis=1dfs(i);}ans[m--]=x;
}int main()
{cin>>m;for(int i=0; i<N; i++) fa[i]=i;for(int i=1; i<=m; i++){scanf("%s",s);g[s[0]][s[1]]=g[s[1]][s[0]]=1;du[s[0]]++;du[s[1]]++;int f1=find(s[0]),f2=find(s[1]);//合并建树fa[f1]=f2;}
//判断是否连通int tmp=0;for(int i=0;i<N;i++)if(fa[i]==i&&du[i])tmp++;if(tmp!=1){cout<<"No Solution";return 0;}
//是否存在欧拉路径	int f=0,rt=0;for(int i=0;i<N;i++){if(du[i]&1){f++;	//一边统计多少个奇数度点,一边找奇数的rt做起点if(!rt)rt=i;}}if(f&&f!=2){cout<<"No Solution";return 0;}
//按照字典序最小开始输出路径if(!rt){//rt不能从0开始for(int i=0;i<N;i++){//按照ASCII找最小的起点rtif(du[i]){rt=i;break;}}}dfs(rt);cout<<ans;}

        

         

旅行计划

 

思路:

题上问以i点为终点的最多游览的城市数。非常类似之前说过的“食物链计数”那道题。

设置f[i]表示以i为终点的最多的游览城市数。那么从入度为0的点开始进行正向topo即可。

顺便再补充一个方向:如果设置f[i]表示以i为起点的最多的游览城市数。那么肯定不能正向topo。

这个时候需要用dfs进行回溯式topo处理。

#include<bits/stdc++.h> 
using namespace std;
const int N=100005;
vector <int>ve[N];
queue<int> q;
int n,m,ans,f[N],in[N],out[N];int main(){cin>>n>>m;int x,y;for(int i=1;i<=m;i++){cin>>x>>y;ve[x].push_back(y);in[y]++;out[x]++;}for(int i=1;i<=n;i++){if(in[i]==0){q.push(i);f[i]=1;}}while(q.size()){//进行拓扑排序int cur=q.front();q.pop();for(int i=0,sz=ve[cur].size();i<sz;i++){int v=ve[cur][i];f[v]=f[cur]+1;in[v]--;if(in[v]==0) q.push(v);}		}for(int i=1;i<=n;i++)cout<<f[i]<<'\n';return 0;
}

        

         

最优贸易

 

思路:

 每个点都可以不卖不买,买,或卖这3种状态,那么分层图自然最合适。

最上面的层之间不论怎么跑动一定不会赚钱或亏钱。只有在层之间移动才能赚钱或亏钱。

也就是层内关系权值为0,层间非0.

然后就转化成spfa求最长路即可。 

#include <bits/stdc++.h> 
using namespace std;
const int N=1e5+5;
int cnt,head[N*3];
int dis[N*3];
bool vis[N*3];
struct Edge{ int to,w,next;}e[250000*3];
void add(int u,int v,int w) { e[++cnt]=(Edge){v,w,head[u]}; head[u]=cnt;}
void spfa(int s)
{memset(dis,-0x3f,sizeof(dis));queue<int>Q;dis[s]=0;vis[s]=1;Q.push(s);while(!Q.empty()){int u=Q.front(); Q.pop();vis[u]=0;for(int i=head[u];i;i=e[i].next){int v=e[i].to,w=e[i].w;if(dis[v]<dis[u]+w) {dis[v]=dis[u]+w;if(vis[v])continue;Q.push(v);vis[v]=1;	}}}    
}int main()
{int n,m,price;cin>>n>>m; for(int i=1;i<=n;i++){cin>>price;add(i,i+n,-price);//在层之间建立关系add(i+n,i+n*2,price);}int u,v,c;for(int i=0;i<m;++i){cin>>u>>v>>c;add(u,v,0);add(u+n,v+n,0);add(u+2*n,v+2*n,0);//建立 分层图(层内图)if(c==2){add(v,u,0);add(v+n,u+n,0);add(v+2*n,u+2*n,0);}}spfa(1);printf("%d",dis[n+2*n]);return 0;
}

然后做完这道题,可以很明显发现和之前做过的“飞行路线”一题很像。那道题中是层内关系的权值非0,层间的关系权值为0,最后在最下面的层找答案即可。本题刚好反过来。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/602547.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MidJourney笔记(10)-faq-fast-help-imagine-info-public-stealth

/faq 在官方 Midjourney Discord 服务器中使用可快速生成流行提示工艺频道常见问题解答的链接。 不过这个命令,我也是没有找到入口,之前还能在MidJourney的频道里使用,然后最近发现没有权限,有点奇怪。不知道系统又做了什么升级。 /fast 切换到快速模式。

Cannot resolve property ‘driverClassName‘

已解决 Cannot resolve property 错误 最近在学习spring时遇到了下面的问题&#xff1a; spring读取不到property的name属性&#xff0c;报红&#xff0c;编译不通过&#xff0c;上网查到了两种解决方案&#xff0c;如下&#xff1a; 1、重新加载spring文件就可以解决问题了&a…

TypeScript 从入门到进阶之基础篇(三) 元组类型篇

系列文章目录 TypeScript 从入门到进阶系列 TypeScript 从入门到进阶之基础篇(一) ts基础类型篇TypeScript 从入门到进阶之基础篇(二) ts进阶类型篇TypeScript 从入门到进阶之基础篇(三) 元组类型篇TypeScript 从入门到进阶之基础篇(四) symbol类型篇 持续更新中… 文章目录 …

VMware Workstation——修改虚拟机配置和设置网络

目录 一、修改配置 1、点击需要修改配置的虚拟机&#xff0c;然后点击编辑虚拟机配置 2、修改内存、CPU、硬盘配置 二、设置网络 1、从虚拟机配置中进入到网络适配器设置 2、选择网络连接模式 一、修改配置 1、点击需要修改配置的虚拟机&#xff0c;然后点击编辑虚拟机配…

Linux系统操作——tcping安装与使用

目录 .一、安装 1、安装依赖 tcptraceroute和bc 2、安装tcping 3、赋予tcping执行权限 4、测试 5、tcping返回结果说明 二、使用说明&#xff08;参数&#xff09; 一、安装 1、安装依赖 tcptraceroute和bc 【 CentOS 或 RHEL】 sudo yum install -y tcptraceroute bc…

听GPT 讲Rust源代码--compiler(25)

File: rust/compiler/rustc_target/src/spec/mod.rs 在Rust的源代码中&#xff0c;rust/compiler/rustc_target/src/spec/mod.rs文件的作用是定义和实现有关目标平台的规范。 SanitizerSet是一个结构体&#xff0c;用于表示目标平台上存在的sanitizer集合。 TargetWarnings是一…

了解统计分析中的岭回归

一、介绍 在统计建模和机器学习领域&#xff0c;回归分析是用于理解变量之间关系的基本工具。在各种类型的回归技术中&#xff0c;岭回归是一种特别有用的方法&#xff0c;尤其是在处理多重共线性和过拟合时。本文深入探讨了岭回归的概念、其数学基础、应用、优点和局限性。 在…

腾讯面试总结

腾讯 一面 mysql索引结构&#xff1f;redis持久化策略&#xff1f;zookeeper节点类型说一下&#xff1b;zookeeper选举机制&#xff1f;zookeeper主节点故障&#xff0c;如何重新选举&#xff1f;syn机制&#xff1f;线程池的核心参数&#xff1b;threadlocal的实现&#xff…

Git 实战指南:常用指令精要手册(持续更新)

&#x1f451;专栏内容&#xff1a;Git⛪个人主页&#xff1a;子夜的星的主页&#x1f495;座右铭&#xff1a;前路未远&#xff0c;步履不停 目录 一、Git 安装过程1、Windows 下安装2、Cent os 下安装3、Ubuntu 下安装 二、配置本地仓库1、 初始化 Git 仓库2、配置 name 和 e…

SpringBoot学习(六)-SpringBoot整合Shiro

12、Shiro 12.1概述 12.1.1简介 Apache Shiro是一个强大且易用的Java安全框架 可以完成身份验证、授权、密码和会话管理 Shiro 不仅可以用在 JavaSE 环境中&#xff0c;也可以用在 JavaEE 环境中 官网&#xff1a; http://shiro.apache.org/ 12.1.2 功能 Authentication…

DFS-体积

DFS-体积 题目&#xff1a; 给出n件物品&#xff0c;每件物品有一个体积Vi&#xff0c;求从中取若干件物品能够组成不同的体积和有多少种可能。例如&#xff0c;n3&#xff0c;Vi(1,3,4),那么输出6,6种不同的体积分别为1,3,4,5,7,8 输入格式&#xff1a; 第一行一个正整数&…

一文讲透Python数据分析可视化之直方图(柱状图)

直方图&#xff08;Histogram&#xff09;又称柱状图&#xff0c;是一种统计报告图&#xff0c;由一系列高度不等的纵向条纹或线段表示数据分布的情况。一般用横轴表示数据类型&#xff0c;纵轴表示分布情况。通过绘制直方图可以较为直观地传递有关数据的变化信息&#xff0c;使…

关于“Python”的核心知识点整理大全65

目录 20.2.19 设置 SECRET_KEY 20.2.20 将项目从 Heroku 删除 注意 20.3 小结 附录 A 安装Python A.1.1 确定已安装的版本 A.1.2 在 Linux 系统中安装 Python 3 A.2 在 OS X 系统中安装 Python A.2.1 确定已安装的版本 A.2.2 使用 Homebrew 来安装 Python 3 注意 …

ejs默认配置 原型链污染

文章目录 ejs默认配置 造成原型链污染漏洞背景漏洞分析漏洞利用 例题 [SEETF 2023]Express JavaScript Security ejs默认配置 造成原型链污染 参考文章 漏洞背景 EJS维护者对原型链污染的问题有着很好的理解&#xff0c;并使用非常安全的函数清理他们创建的每个对象 利用Re…

高校选课系统需求分析开发源码

高校学生选课报名系统包括学生、教师和管理员三方的功能需求&#xff0c;学生的需求是查询院系的课程、选课情况及个人信息修改&#xff1b;教师则需要查看和查询所有课程信息及自己的课程信息以及教师信息的修改&#xff1b;管理员则负责更为复杂的任务&#xff0c;包括对学生…

opencv007 图像运算——加减乘除

今天学习图像处理的基础——加减乘除&#xff0c;总体来说比较好理解&#xff0c;不过生成的图片千奇百怪哈哈哈哈 opencv中图像的运算本质是矩阵的运算 加法 做加法之前要求两张图片形状&#xff0c;长宽&#xff0c;通道数完全一致 cv2.add(img1, img2) add的规则是两个图…

HTML 使用 ruby 给汉字加拼音

使用 ruby 给汉字加拼音 兼容性 使用 ruby 给汉字加拼音 大家有没有遇到过要给汉字头顶上加拼音的需求? 如果有的话, 你是怎么解决的呢? 如果费尽心思, 那么你可能走了很多弯路, 因为 HTML 原生就有这样的标签来帮我们实现类似的需求. <ruby> ruby 本身是「红宝石」…

leetcode 每日一题 2023年12月30日 一周中的第几天

题目 给你一个日期&#xff0c;请你设计一个算法来判断它是对应一周中的哪一天。 输入为三个整数&#xff1a;day、month 和 year&#xff0c;分别表示日、月、年。 您返回的结果必须是这几个值中的一个 {"Sunday", "Monday", "Tuesday", &qu…

transforms图像增强(二)

一、图像变换 1、transforms.Pad transforms.Pad是一个用于对图像边缘进行填充的数据转换操作。 参数&#xff1a; padding&#xff1a;设置填充大小。可以是单个整数&#xff0c;表示在上下左右四个方向上均填充相同数量的像素&#xff1b;也可以是一个包含两个整数的元组…

【Xilinx FPGA】异步 FIFO 的复位

FIFO&#xff08;First-In-First_Out&#xff0c;先入先出&#xff09;是一种的存储器类型&#xff0c;在 FPGA 开发中通常用于数据缓存、位宽转换或者跨时钟域&#xff08;多 bit 数据流&#xff09;。在使用异步 FIFO 时&#xff0c;应注意复位信号是否遵循相关要求和规范&am…