Nebius Welcome Round (Div. 1 + Div. 2) E. Routing(状压dp/找到一个无向图简单环,使得所有点到环的距离不超过1)

文章介绍了一个关于无向图的问题,给定一个无自环、无重边、连通的无向图,需要找到一种方式构建邻接关系,使得从任意点出发都能通过DFS找到其他任何点。这个问题被转化为寻找图中的简单环,使得所有点到环的距离不超过1。通过状压DP和DFS算法,可以在O(2^20*20*20)的时间复杂度内解决,代码中使用了前驱节点记录和可达状态集合来实现。

题目

原题意比较难读,简单用自己的话翻译一下

给定一个n(n<=20)个点,m(n-1<=m<=C(n,2))条边,无自环、无重边、连通的无向图,

Ada从u找v的路径的流程,可以看做是以下这个函数

dfs(u):

1. 判断v是不是u的直连点,是的话,结束流程,返回u->v

2. 若第一步没找到,则从u走到a(u)上,再dfs(a[u])

若找到,函数返回u到v的路径,即dfs(u)=u->a(u)+dfs(a[u])

对于每个点u,构造a(u),要求u-a(u)的边在图上存在(有点竞赛图定向的意思)

使得从任意一个点u出发找v,都能找到,即函数不会死循环,输出a数组

思路来源

乱搞AC

题解

Codeforces Beta Round #11 D. A Simple Task(状压dp/无向图简单环的个数)_Code92007的博客-优快云博客

可以发现,从任意一个点u出发,要找的点v,要么在u->a(u)的路径上,要么是a(u)的相邻点

这等价于,找到一个无向图简单环,使得所有点到环的距离不超过1,

可证充要性,如果存在v的距离>1则u找不到v,如果不存在的话所有点都能找到

让在环上的点形成一个环,不在环上的点往环上指即可

这里用到了完全图找环的技巧,即相同的环从环上最小点出发

原题中会减去环长为2的环,并答案除以2,因为顺逆时针各会统计一次,

本题中,环长为2的点也是答案,并且找到一个合法的环即可

做法是O(2^20*20*20)的,因为无自环重边,20*20实际是C(20,2)=190,2s可以通过

pre记录了一下转移前驱,can记录了一下当前状态dis<=1的可达点,是全集则表明合法

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> P;
#define pb push_back
const int N=20,M=1<<20;
ll dp[M][N],can[M],ans;//dp[i][j]表示当前从lowbit(i)出发,访问了i内的点,且到达j的简单路径数
P pre[M][N];
int n,m,u,v,all,res[N];
vector<int>e[N];
int main(){
	memset(res,-1,sizeof res);
    scanf("%d%d",&n,&m);
    for(int i=0;i<n;++i){
    	can[1<<i]|=(1<<i);
    }
    for(int i=1;i<=m;++i){
        scanf("%d%d",&u,&v);
        u--;v--;
        can[1<<u]|=(1<<v);
        can[1<<v]|=(1<<u);
        e[u].pb(v);e[v].pb(u);
    }
    for(int i=0;i<n;++i){
        dp[1<<i][i]=1;
    }
    int up=1<<n;
    for(int i=1;i<up;++i){
    	for(int j=0;j<n;++j){
    		if(i>>j&1){
    			can[i]=can[i^(1<<j)]|can[1<<j];
    			break;
    		}
    	}
    }
    for(int i=1;i<up;++i){
        for(int j=0;j<n;++j){
            if(!dp[i][j])continue;
            for(int k=0;k<e[j].size();++k){
                int v=e[j][k];
                if((i&(-i))>(1<<v))continue;
                if(i&(1<<v)){
                    if((i&(-i))==(1<<v)){
                        if(can[i]==up-1){
                        	//printf("i:%d j:%d\n",i,j);
                        	puts("Yes");
                        	//printf("v:%d j:%d\n",v,j);
                        	res[v]=j;
                        	for(int x=i,y=j,px,py;x;x=px,y=py){
                        		px=pre[x][y].first,py=pre[x][y].second;
                        		if(!px)break;
                        		res[y]=py;
                        		//printf("x:%d y:%d px:%d py:%d\n",x,y,px,py);
                        	}
                        	for(int l=0;l<n;++l){
                        		if(res[l]==-1){
                        			for(auto &v:e[l]){
                        				if(i&(1<<v)){
                        					res[l]=v;
                        					break;
                        				}
                        			}
                        		}
                        	}
                        	for(int l=0;l<n;++l){
                        		printf("%d%c",res[l]+1," \n"[l==n-1]);
                        	}
                        	return 0;
                        }
                    }
                }
                else{
                    dp[i|(1<<v)][v]+=dp[i][j];
                    pre[i|(1<<v)][v]=P(i,j);
                }
            }
        }
    }
    puts("No");
    return 0;
}

 

 

 

### 关于 `com.google.maps.routing.v2` 包的功能与用途 在 Spring Boot 项目中,如果需要使用谷歌地图的高级路由功能,则可以引入 `com.google.maps.routing.v2` 包。此包隶属于 Google 官方提供的 Java 客户端库——Google Maps Services for Java[^1]。以下是该包的主要功能及其具体用途: #### 主要功能 - **路线规划 (Directions API)**:支持计算两个或多个地理位置之间的最佳路径,并可选择同的交通模式(步行、驾车、骑行等),同时允许设置出发时间、避开收费路段等功能。 - **距离矩阵 (Distance Matrix API)**:用于批量计算多个起和终之间的时间和距离信息,适用于物流配送场景下的优化调度算法设计。 - **几何编码/解码 (Geocoding & Reverse Geocoding APIs)**:将物理地址转换成经纬度坐标或者反之亦然的操作也包含在此模块之内。 这些特性使得开发者能够轻松构建基于位置的服务应用而无需关心底层复杂的网络协议细节处理过程[^2]。 #### 实际应用场景举例说明 假设我们需要创建一个简单的 Web 应用程序来展示从当前位置到达目的地的最佳行车线路图示例代码如下: ```java import com.google.maps.GeoApiContext; import com.google.maps.DirectionsApi; import com.google.maps.model.*; public class RouteExample { public static void main(String[] args) throws Exception { GeoApiContext context = new GeoApiContext.Builder() .apiKey("YOUR_API_KEY") // 替换为您的API密钥 .build(); DirectionsResult result = DirectionsApi.newRequest(context) .origin(new LatLng(37.422,-122.084))//起始纬经度 .destination(new LatLng(37.429,-122.145))//目标地纬经度 .mode(TravelMode.DRIVING)//设定旅行方式为驾驶汽车形式移动 .await();//同步等待结果返回 System.out.println(result.routes[0].overviewPolyline.decodePath()); } } ``` 上面这段小程序演示了如何调用方向服务接口并打印出概览多边形路径集合列表[^3]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小衣同学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值