首页 > 其他分享 >CF1253F Cheap Robot

CF1253F Cheap Robot

时间:2025-01-20 13:34:46浏览次数:1  
标签:int max maxm Cheap Robot CF1253F 充电站 ans dis

Cheap Robot

题目翻译:

给一个带$N$个点的带权无向连通图,并给定$k$每经过一个边就要消耗边的边权$w$,而当到达$1 \sim k$的节点处可以将点充满。求从$a$到$b$所需要的最小点容量$c$。及一次性消耗的电量不能超过$c$。

前置知识:

$1.$最近公共祖先$LCA$

$2.$最小生成树$kruskal$

$3.$并查集

$4.$最短路$dijkstra$

思路:

普通解法:

我们读完题肯定可以想到,用全源最短路求$1 \sim k$的最短路,再求每个节点所邻的最近的充电节点,求出里面耗电的最大值最小即可,但这样复杂度就到了$n^2logn$,肯定会超

正解:

1.我们在仔细思考会发现,我们要尽量把机器人移到充电站,在在充电站之间移动一般是最优的,因此我们可以预处理出每个节点离充电站的最小距离$dis_i$。那如何求了。我们可以先建一个超级原点$0$号点,它与所有充电站,即$1 \sim k$有一条边权为零的边,则由这个点到任意节点的最短路就是这个节点到最近充电站的距离。原因是,任意非充电站节点到超级原点必经过充电站,而充电站到超级原点的边权为零,则该点到超级原点的最短路等于到充电站的最短路。因此只需跑一遍$dijkstra$求出$dis_i$即可。

建边

for(int i=1;i<=m;i++){
	int u,v,w;
	cin>>u>>v>>w;
	e[u].push_back({v,w});
	e[v].push_back({u,w});
}
for(int i=1;i<=k;i++){
	e[0].push_back({i,0});
}

$dijkstra$


int dis[N],vis[N];
vector<edge>e[N];
priority_queue<node>q;
void dijkstra(){
	memset(dis,0x3f,sizeof(dis));
	dis[0]=0;
	q.push({0,0});
	while(!q.empty()){
		int u=q.top().u;
		q.pop();
		if(vis[u])continue;
		vis[u]=1;
		for(auto ed:e[u]){
			int v=ed.v,w=ed.w;
			if(dis[v]>dis[u]+w){
				dis[v]=dis[u]+w;
				q.push({v,dis[v]});
			}
		}
	}
}

2.又由已知条件,$c$,当前剩余电量$k$,和点离充电站的最短路$dis_i$可得出关系
$$$c \geq x \geq dis_i$$$
而从充电站走到点至少消耗了$dis_i$则不等式可以改为
$$$c-dis_i \geq x \geq dis_i$$$
令下一个点为$j$边权为$w_{i,j}$,同理有
$$$c-dis_j \geq x-w_{i,j} \geq dis_j$$$
将两个式子合并即可得到
$$$dis_j \le c-dis_i-w_{i,j}$$$
简单转换可知
$c \geq dis_i+dis_j+w_{i,j}$
则由此可知从$i$到$j$的最小消耗电量为$dis_i+dis_j+w_{i,j}$。


3.既然已经求出两点之间的最小消耗电量,而题目又是多次询问,求最大电容量及从$a$到$b$的每条路的最大耗电量的最小值,因此我们可以先将任意两点之间的边权换成$dis_i+dis_j+w_{i,j}$,在跑一遍$kruskal$求出最小生成树。在求任意两点路径上边权的最大值即可


建新图

for(int u=1;u<=n;u++){
	for(auto ed:e[u]){
		now.push_back({u,ed.v,ed.w+dis[u]+dis[ed.v]});
	}
}

$kruskal$


int fa[N];
int find(int x){
	if(fa[x]==x)return x;
	else return fa[x]=find(fa[x]);
}
void kruskal(){
	sort(now.begin(),now.end(),cmp);
	for(int i=1;i<=n;i++){
		fa[i]=i;
	}
	int cnt=0;
	for(auto ed:now){
		if(find(ed.u)!=find(ed.v)){
			cnt++;
			tr[ed.u].push_back({ed.v,ed.w});
			tr[ed.v].push_back({ed.u,ed.w});
			fa[find(ed.u)]=find(ed.v);
			if(cnt==n-1)break;
		}
	}
}

4.要求树上的路径问题,我们可以简单想到求$LCA$,于是直接用倍增求$LCA$,只需要将求和改为求$max$即可


$LCA$

int f[N][22];
int deep[N],maxm[N][22];
void init(){
	for(int i=1;i<=20;i++){
        for(int j=1;j<=n;j++){
            f[j][i]=f[f[j][i-1]][i-1];
            maxm[j][i]=max(maxm[j][i-1],maxm[f[j][i-1]][i-1]);
        }
	}
}
void dfs(int p,int father){
    f[p][0]=father;
	for(auto ed:tr[p]){
		int v=ed.v,w=ed.w;
        if(v==father)continue;
		maxm[v][0]=w;
		deep[v]=deep[p]+1;
		dfs(v,p);
	}
}
int lca(int x,int y){
	int ans=0;
	if(deep[x]<deep[y])swap(x,y);
	for(int i=20;i>=0;i--){
		if(deep[f[x][i]]<deep[y]) continue;
		ans=max(ans,maxm[x][i]);
		x=f[x][i];
	}
	if(x==y) return ans;
	for(int i=20;i>=0;i--){
		if(f[x][i]==f[y][i])continue;
		ans=max(ans,max(maxm[x][i],maxm[y][i]));
		x=f[x][i];
		y=f[y][i];
	}
	ans=max(ans,max(maxm[x][0],maxm[y][0]));
	return ans;
}

完整流程:

$1.$建图,并将所有$1 \sim k$的点连向超级原点,边权为零
$2.$跑一遍以超级原点为起点的$dijkstra$,求出$dis_i$
$3.$将任意两点间边的边权改为$dis_i+dis_j+w_{i,j}$,建立新图
$4.$跑一遍新图$kruskal$求出最小生成树
$5.$在最小生成树上求$LCA$,维护路径中边权的最大值,并输出结果

完整代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
struct edge{
	int v,w;
}; 
struct node{
	int u,dis;
	bool operator<(const node &a)const{return dis>a.dis;}
};
struct E{
	int u,v,w;
};
bool cmp(E x,E y){
	return x.w<y.w;
}
vector<E>now;
vector<edge>tr[N];
int n,m;
int dis[N],vis[N];
vector<edge>e[N];
priority_queue<node>q;
void dijkstra(){
	memset(dis,0x3f,sizeof(dis));
	dis[0]=0;
	q.push({0,0});
	while(!q.empty()){
		int u=q.top().u;
		q.pop();
		if(vis[u])continue;
		vis[u]=1;
		for(auto ed:e[u]){
			int v=ed.v,w=ed.w;
			if(dis[v]>dis[u]+w){
				dis[v]=dis[u]+w;
				q.push({v,dis[v]});
			}
		}
	}
}
int fa[N];
int find(int x){
	if(fa[x]==x)return x;
	else return fa[x]=find(fa[x]);
}
int f[N][22];
int deep[N],maxm[N][22];
void init(){
	for(int i=1;i<=20;i++){
        for(int j=1;j<=n;j++){
            f[j][i]=f[f[j][i-1]][i-1];
            maxm[j][i]=max(maxm[j][i-1],maxm[f[j][i-1]][i-1]);
        }
	}
}
void dfs(int p,int father){
    f[p][0]=father;
	for(auto ed:tr[p]){
		int v=ed.v,w=ed.w;
        if(v==father)continue;
		maxm[v][0]=w;
		deep[v]=deep[p]+1;
		dfs(v,p);
	}
}
int lca(int x,int y){
	int ans=0;
	if(deep[x]<deep[y])swap(x,y);
	for(int i=20;i>=0;i--){
		if(deep[f[x][i]]<deep[y]) continue;
		ans=max(ans,maxm[x][i]);
		x=f[x][i];
	}
	if(x==y) return ans;
	for(int i=20;i>=0;i--){
		if(f[x][i]==f[y][i])continue;
		ans=max(ans,max(maxm[x][i],maxm[y][i]));
		x=f[x][i];
		y=f[y][i];
	}
	ans=max(ans,max(maxm[x][0],maxm[y][0]));
	return ans;
}
void kruskal(){
	sort(now.begin(),now.end(),cmp);
	for(int i=1;i<=n;i++){
		fa[i]=i;
	}
	int cnt=0;
	for(auto ed:now){
		if(find(ed.u)!=find(ed.v)){
			cnt++;
			tr[ed.u].push_back({ed.v,ed.w});
			tr[ed.v].push_back({ed.u,ed.w});
			fa[find(ed.u)]=find(ed.v);
			if(cnt==n-1)break;
		}
	}
}
signed main(){
	int k,q;
	cin>>n>>m>>k>>q;
	for(int i=1;i<=m;i++){
		int u,v,w;
		cin>>u>>v>>w;
		e[u].push_back({v,w});
		e[v].push_back({u,w});
	}
	for(int i=1;i<=k;i++){
		e[0].push_back({i,0});
	}
	dijkstra();
	for(int u=1;u<=n;u++){
		for(auto ed:e[u]){
			now.push_back({u,ed.v,ed.w+dis[u]+dis[ed.v]});
		}
	}
	kruskal();
	deep[1]=1;
	dfs(1,-1);
    init();
	
	while(q--){
		int x,y;
		cin>>x>>y;
		cout<<lca(x,y)<<endl;
	}
}

标签:int,max,maxm,Cheap,Robot,CF1253F,充电站,ans,dis
From: https://www.cnblogs.com/XichenOC/p/18681142

相关文章

  • 说说你对robots文件的理解,它有什么作用?
    robots.txt文件是一个用于指示搜索引擎机器人(也称为爬虫或网络爬虫)如何与网站进行交互的文本文件。它通常位于网站的根目录中,并通过标准的HTTP协议进行访问。虽然robots.txt文件不是强制性的,但它为网站管理员提供了一种方式来控制哪些搜索引擎机器人可以访问网站的哪些部分,以及它......
  • 4. gazebo仿真环境中添加robotiq 2f 140的gripper_controller控制器
    原文地址:gazebo仿真环境中添加robotiq2f140的gripper_controller控制器gazebo仿真环境中添加robotiq2f140的gripper_controller控制器搭建环境:ubuntu:20.04ros:Noneticsensor:robotiq_ft300gripper:robotiq_2f_140_gripperUR:UR3reasense:D435i通过下面几篇博客配置......
  • 3. ur3+robotiq ft sensor+robotiq 2f 140+realsense d435i配置rviz,gazebo仿真环境
    原文地址:ur3+robotiqftsensor+robotiq2f140+realsensed435i配置rviz,gazebo仿真环境ur3+robotiqftsensor+robotiq2f140+realsensed435i配置rviz,gazebo仿真环境搭建环境:ubuntu:20.04ros:Noneticsensor:robotiq_ft300gripper:robotiq_2f_140_gripperUR:UR3reasens......
  • 2. ur3+robotiq ft sensor+robotiq 2f 140配置gazebo仿真环境
    原文地址:ur3+robotiqftsensor+robotiq2f140配置gazebo仿真环境ur3+robotiqftsensor+robotiq2f140配置gazebo仿真环境搭建环境:ubuntu:20.04ros:Noneticsensor:robotiq_ft300gripper:robotiq_2f_140_gripperUR:UR3通过上一篇博客配置好ur3、力传感器和robotiq夹爪......
  • ur3+robotiq ft sensor+robotiq 2f 140配置rviz仿真环境-
    原文地址:ur3+robotiqftsensor+robotiq2f140配置rviz仿真环境ur3+robotiqftsensor+robotiq2f140配置rviz仿真环境搭建环境:ubuntu:20.04ros:Noneticsensor:robotiq_ft300gripper:robotiq_2f_140_gripperUR:UR3在安装sensor和gripper之前,先简单配置一下UR机械臂的......
  • ROS-noetic+UR5上安装robotiq_85_gripper夹爪
    夹抓(未配置控制器,无中间过程)ROS-noetic+UR5上安装robotiq_85_gripper夹爪 夹抓(可运行,详细配置过程,依赖最新代码)在UR5机械臂末端添加robotiq2f85夹爪并在Gazebo中仿真 相机+夹抓+待抓取物体(可直接运行,无中间过程)ros1noetic跑UR5_gripper_camera_gazebo 相机+......
  • 在UR5机械臂末端添加robotiq 2f 85夹爪并在Gazebo中仿真
    原文连接:在UR5机械臂末端添加robotiq2f85夹爪并在Gazebo中仿真需求在UR5机械臂末端添加robotiq2f85夹爪并在Gazebo中仿真环境ubuntu20.04+ROS1noetice准备工作创建工作空间mkdir-pcatkin_UR5/src进入catkin_UR5/src目录,分别下载机械臂和夹爪对应的功能包cd......
  • [ABC216H] Random Robots
    [ABC216H]RandomRobots题意有\(k\)个机器人在数轴上,位置分别是\(x_1,x_2,\dots,x_k\),\(x\)均为整数.接下来\(n\)秒,每秒每个机器人有\(\dfrac{1}{2}\)的概率不动,\(\dfrac{1}{2}\)的概率往坐标轴正方向移动一个单位距离,机器人的移动同时进行.求机器人互相......
  • OCS2::legged_robot::LeggedRobotInterface.cpp
    这个文件主要是对最优问题的构造。1.setupOptimalConrolProblemvoidLeggedRobotInterface::setupOptimalConrolProblem(conststd::string&taskFile,conststd::string&urdfFile,conststd::string&referenceFile,......
  • Active Pose Relocalization for Intelligent Substation Inspection Robot
    (未完成:加思维导图、段落分析、pipeline)ActivePoseRelocalizationforIntelligentSubstationInspectionRobot智能变电站巡检机器人主动姿态重定位摘要:变电站中广泛应用的智能巡检机器人在对电气设备进行日常巡检时,要求采集与标定图像一致的巡检图像。然而,由于导航......