建图+二分图+二分

//#define LOCAL
#include <bits/stdc++.h>

using namespace std;
#define ll long long
#define mem(a, b) memset(a,b,sizeof(a))
#define INF 0x3f3f3f3f
#define DNF 0x7f
#define DBG printf("this is a input\n")
#define fi first
#define se second
#define mk(a, b) make_pair(a,b)
#define pb push_back
#define p_queue priority_queue
#define eps 1e-8
ll gcd(ll a, ll b) {
    return b == 0 ? a : gcd(b, a % b);
}

ll lcm(ll a, ll b) {
    return a / gcd(a, b) * b;
}
int n , m, cx;
double t1, t2, v;
int head[100005] , cnt;
double dis[55][55];
struct node{
    double x, y;
}r[55], f[55];
struct e
{
    int t, next;
}edge[1000*1000];
void add(int f, int t)
{
    edge[cnt].t = t;
    edge[cnt].next = head[f];
    head[f] = cnt ++;
}
int fa[100005] , vis[100005];
double DIS(int i , int j)
{
    return sqrt ((f[i].x - r[j].x)*(f[i].x - r[j].x) + (f[i].y - r[j].y)*(f[i].y - r[j].y) );
}
bool dfs(int root)
{
    for(int i = head[root] ; i != -1 ; i = edge[i].next)
    {
        int t = edge[i].t;
        if(!vis[t])
        {
            vis[t] = 1;
            if(!fa[t] || dfs(fa[t]))
            {
                fa[t] = root;
                return true;
            }
        }
    }
    return false;
}
bool check(double x)
{
    mem(head,-1);
    cnt = 0;
    cx = 0;
    for(int i = 1 ; i <= n ; i ++) //防御
    {
        double now = t1;
        while(now <= x)
        {
            cx ++;
            for(int j = 1 ; j <= m ; j ++) //敌人
            {
                if(dis[i][j]/v + now <= x)
                    add(cx, j); //i j 都有可能为相同值故双向边会出错,除非编号不相同
            }
            now += (t2+t1);
        }
    }
    mem(fa,0);
    int ans = 0;
    for(int i = 1 ; i <= cx ; i ++)
    {
        mem(vis,0);
        if(dfs(i)) ans ++;
        if(ans == m) return true;
    }
    return false;
}
int main(void)
{
#ifdef LOCAL
    freopen("data.in", "r", stdin);
    freopen("odata.out", "w", stdout);
#endif
    cin>>n>>m>>t1>>t2>>v;
    t1 /= 60.0;
    for(int i = 1 ; i <= m ; i ++)
        cin>>r[i].x>>r[i].y;
    for(int i = 1 ; i <= n ; i ++)
        cin>>f[i].x>>f[i].y;
    for(int i = 1 ; i <= n ; i ++)
        for(int j = 1; j <= m ; j ++)
            dis[i][j] = DIS(i,j);
    double l = 0 , r = 100000.0;
    while(r - l > eps)
    {
        double mid = (l + r) / 2.0;
        if(check(mid)) r = mid;
        else l = mid;
    }
    printf("%.6lf\n",r);
}

 

基于STM32 F4的永磁同步电机无位置传感器控制策略研究内容概要:本文围绕基于STM32 F4的永磁同步电机(PMSM)无位置传感器控制策略展开研究,重点探讨在不依赖物理位置传感器的情况下,如何通过算法实现对电机转子位置和速度的精确估计与控制。文中结合嵌入式开发平台STM32 F4,采用如滑模观测器、扩展卡尔曼滤波或高频注入法等先进观测技术,实现对电机反电动势或磁链的估算,进而完成无传感器矢量控制(FOC)。同时,研究涵盖系统模、控制算法设计、仿真验证(可能使用Simulink)以及在STM32硬件平台上的代码实现与调试,旨在提高电机控制系统的可靠性、降低成本并增强环境适应性。; 适合人群:具备一定电力电子、自动控制理论基础和嵌入式开发经验的电气工程、自动化及相关专业的研究生、科研人员及从事电机驱动开发的工程师。; 使用场景及目标:①掌握永磁同步电机无位置传感器控制的核心原理与实现方法;②学习如何在STM32平台上进行电机控制算法的移植与优化;③为开发高性能、低成本的电机驱动系统提供技术参考与实践指导。; 阅读议:议读者结合文中提到的控制理论、仿真模型与实际代码实现进行系统学习,有条件者应在实验平台上进行验证,重点关注观测器设计、参数整定及系统稳定性分析等关键环节。
<think> 首先,用户的问题是:理解给定代码如何判断一个n个点m条边的无向(可能存在重边和自环)是否为二分图,以及该算法的原理和代码实现细节。用户特别提到使用深度优先搜索(DFS)。 从用户提供的引用中,我有一些相关信息: - 引用[1]提到深度优先搜索在遍历中的应用。 - 引用[2]是关于深度优先搜索的实现和路径查找。 - 引用[4]提供了DFS的代码实现示例,用于查找路径。 用户的问题集中在判断无向是否为二分图二分图是指一个的所有顶点可以被划分为两个互不相交的子集(比如U和V),使得每条边都连接U中的一个顶点和V中的一个顶点;也就是说,中没有奇环。 使用DFS来判断是否为二分图的原理: - 二分图的充要条件是可以被双着色(即用两种颜色涂色),使得任意相邻顶点颜色不同。 - DFS可以用来进行的双着色检测:从任意顶点开始,给它涂一种颜色(比如颜色0),然后它的邻居涂另一种颜色(颜色1),邻居的邻居又涂颜色0,依此类推。 - 如果在DFS过程中,发现某个顶点的邻居已经被涂色,并且颜色与当前顶点相同,那么这个就不是二分图。 - 此外,由于可能不连通,需要对每个连通分量都进行检查。 现在,用户提到了“给定代码”,但没有提供代码。用户说:“给定代码如何判断”,但在问题中没有显示代码。回顾用户消息: - “我想理解给定代码如何判断...” - 但在用户的消息中,没有提供具体的代码。用户可能是在指引用中的代码,但引用[4]中的代码是用于查找路径的,不是直接判断二分图的。 - 我需要基于DFS算法来解释原理和实现细节,因为用户提到了“使用深度优先搜索”。 用户引用了几个部分: - 引用[4]中有一个DFS实现用于路径查找,但可以适配。 - 用户指定了条件:n个点m条边的无向,可能存在重边和自环。 关键点: - 自环:如果存在自环(顶点连接到自身),那么不可能被二分图,因为无法满足双着色(同一个顶点不能有两种颜色)。 - 重边:多边可能影响,但DFS可以处理,因为我们只看相邻顶点。 算法步骤: 1. 初始化:创颜色数组color,大小为n(顶点数),初始化为-1(表示未着色)。创一个visited数组来跟踪访问状态(但DFS中着色也可以替代)。 2. 遍历每个顶点:如果顶点未着色,启动DFS。 3. 在DFS中: - 为当前顶点着色(假设当前颜色为c)。 - 遍历所有邻居: - 如果邻居未着色,DFS递归邻居,使用颜色1-c。 - 如果邻居着色且颜色等于当前顶点颜色,则不是二分图;返回false。 4. 对所有连通分量重复。 实现细节: - 需要处理的不连通性。 - 自环:在DFS前检查是否有自环。如果有,直接返回false。 - 重边:不影响着色,因为我们只关心邻居顶点的颜色。 代码实现:用户可能需要伪代码或具体语言实现。既然引用中有Java代码,我可以参考那个风格。 从引用[4]的代码: ```c void FindPath(AGraph *G,int u,int v,int path[],int d){ // ... } ``` 但这不是用于二分图的。我需要基于DFS实现一个判断二分图的函数。 用户要求回答的结构: - 回答结构清晰,帮助用户逐步解决问题。 - 使用中文。 - 对于数学表达式,使用$...$或$$...$$。 - 生成相关问题。 我的回答结构: 1. **解释原理**:简述二分图的定义和DFS如何检测。 2. **算法步骤**:逐步描述DFS判断二分图的过程。 3. **代码实现细节**:提供伪代码或具体语言实现,并解释关键部分。 4. **处理特殊条件**:如重边和自环。 5. **生成相关问题**:最后添加相关问题。 原理: - 二分图可以被划分为两个独立集。 - 定理:二分图当且仅当它不包含奇环。 - DFS实现双着色:如果着色冲突,说明有奇环。 针对自环:如果一个顶点有自环,那么它连接到自身,所以在着色时,它无法满足不同颜色,直接不是二分图。 重边:多个边连接到同一个顶点,但着色时只需检查颜色是否冲突。 代码实现: - 假设用邻接表表示。 - 创一个数组color[],索引从0到n-1,初始化-1。 - 对于每个顶点i from 0 to n-1: - 如果color[i] == -1: - 调用DFS(i, 0) // 起始颜色0 - 如果DFS返回false,则整个不是二分图。 - DFS函数:dfs(int u, int c) - 设置color[u] = c - 对于u的每个邻居v: - 如果color[v] == -1: // 未着色 - 如果dfs(v, 1-c) 返回false,则返回false - 否则如果color[v] == c: // 冲突 - 返回false - 返回true 在DFS前,检查自环:遍历所有顶点,如果任何顶点有边到自身(邻接表中包含u本身),则直接返回false。 在邻接表表示中,自环会出现在邻接列表里,所以当遍历邻居时,如果v == u,那么着色冲突会发生,因为color[u]已经设置,而color[v]==color[u]。 所以不需要额外检查自环;着色过程会自动检测到。 重边:在邻接表中可能有重复项,但着色逻辑相同。 实现细节: - 由于可能大,使用递归DFS可能有栈溢出风险,但通常对于中等大小没问题。 - 可以用迭代DFS(使用栈)来避免递归深度。 现在,回答用户: - 用户提到“给定代码”,但没有提供,所以我将描述一般实现。 - 参考引用[4],我可以类似地写一个函数。 伪代码/代码示例: 我可以用类似引用[4]的风格写一个C-like代码,但用户问题中涉及Java(引用[2]),所以或许用Java。 既然用户是中文,我可以提供一个通用的实现。 最终回答: - 开头解释。 - 步骤。 - 代码示例。 - 解释。 - 相关问题。 生成相关问题: 基于内容,如: 1. 如何使用广度优先搜索判断二分图? 2. 二分图的实际应用场景? 3. 如何处理大型的DFS以避免栈溢出? </think> ### 深度优先搜索判断无向是否为二分图的原理及实现细节 用户的问题聚焦于如何利用深度优先搜索(DFS)判断一个给定无向(包含 $n$ 个顶点和 $m$ 条边,可能含重边和自环)是否为二分图。以下是清晰、逐步的解释,包括算法原理、实现细节和代码示例。算法核心基于 **双着色检测**:二分图的充要条件是中不存在奇环(即长度为奇数的环),这等价于可以被两种颜色(如0和1)着色,使得任意相邻顶点颜色不同[^1]。 #### 算法原理 1. **二分图的定义**: - 一个无向 $G = (V, E)$ 是二分图,当且仅当它的顶点集 $V$ 可以被划分为两个互不相交的子集 $U$ 和 $V$,使得每条边 $(u,v) \in E$ 都满足 $u \in U$ 且 $v \in V$(或反之)。 - 数学等价表述:可双着色,即存在函数 $c: V \to \{0,1\}$,使得对所有边 $(u,v)$,有 $c(u) \neq c(v)$[^1]。 2. **DFS检测原理**: - DFS遍历,并为每个顶点着色(起始颜色设为0)。 - 对当前顶点 $u$,给其所有未着色邻居 $v$ 递归着色为 $1 - c(u)$。 - 如果发现某个邻居 $v$ 已着色且 $c(v) = c(u)$,则着色冲突,表明存在奇环,不是二分图。 - 由于可能不连通,需对每个连通分量独立执行DFS[^2][^4]。 3. **处理特殊条件**: - **自环**:如果顶点存在自环(即边 $(u,u)$),则无法满足 $c(u) \neq c(u)$,直接判定非二分图。 - **重边**:多条边连接同一对顶点不影响着色逻辑,DFS在遍历邻居时自动处理重边(颜色冲突检测仍有效)。 - **不连通**:遍历所有顶点,对未着色顶点启动DFS,确保覆盖所有连通分量。 #### 算法步骤 1. **初始化**: - 创颜色数组 `color[]`,大小为 $n$(顶点数),初始化所有元素为 $-1$(表示未着色)。 - 可选:创 `visited` 数组,但着色本身可替代访问标记。 2. **遍历顶点**: - 对每个顶点 $i$(从0到 $n-1$): - 如果 `color[i] == -1`(未着色),调用 `dfs(i, 0)`(起始颜色0)。 - 如果DFS返回 `false`,则二分图,提前结束。 3. **DFS递归过程**: - 为当前顶点 $u$ 着色为 $c$。 - 遍历 $u$ 的所有邻居 $v$: - 如果 $v$ 未着色(`color[v] == -1`),递归调用 `dfs(v, 1 - c)`。 - 如果递归返回 `false`,则向上传播 `false`。 - 如果 $v$ 已着色且 `color[v] == c`,检测到冲突,返回 `false`(非二分图)。 - 若所有邻居无冲突,返回 `true`。 4. **终止条件**: - 整个遍历结束后无冲突,则二分图。 - 自环处理:在DFS遍历邻居时,如果 $v = u$(自环),自动触发 `color[v] == c(u)`,返回 `false`,无需额外检查。 #### 代码实现细节 以下是用类C语言(基于引用[4]的结构)实现的代码。使用 **邻接表** 表示(适合稀疏),顶点编号从0开始。代码包括详细注释,解释关键部分。 ```c #include <stdio.h> #include <stdlib.h> #define MAX_N 100000 // 假设最大顶点数 // 的邻接表结构(与引用[4]类似) typedef struct ArcNode { int adjvex; // 邻接顶点索引 struct ArcNode *nextarc; // 指向下一条边 } ArcNode; typedef struct VNode { ArcNode *firstarc; // 指向第一条边 } VNode; typedef struct { VNode adjlist[MAX_N]; // 邻接表数组 int n, m; // 顶点数和边数 } AGraph; // DFS着色函数:判断从u开始的连通分量是否为二分图 // 参数:G, 当前顶点u, 当前颜色c, 颜色数组color int dfs(AGraph *G, int u, int c, int color[]) { color[u] = c; // 给顶点u着色为c(0或1) ArcNode *p = G->adjlist[u].firstarc; while (p != NULL) { int v = p->adjvex; // 邻居顶点v if (color[v] == -1) { // v未着色:递归着色 if (!dfs(G, v, 1 - c, color)) // 邻居着相反颜色1-c return 0; // 若递归冲突,返回false } else if (color[v] == c) { // v已着色且颜色冲突 return 0; // 非二分图 } p = p->nextarc; // 处理下一条边(重边自动处理) } return 1; // 当前分量无冲突 } // 主函数:判断整个是否为二分图 int isBipartite(AGraph *G) { int color[MAX_N]; for (int i = 0; i < G->n; i++) { color[i] = -1; // 初始化所有顶点未着色 } for (int i = 0; i < G->n; i++) { if (color[i] == -1) { // 未着色顶点(新连通分量) if (!dfs(G, i, 0, color)) { // 启动DFS,起始颜色0 return 0; // 任意分量冲突,返回false } } } return 1; // 全无冲突,是二分图 } // 示例:构并调用 int main() { AGraph G; // 初始化(省略具体代码,参考引用[4]) // 例如:输入顶点数G.n, 边数G.m,填充邻接表 if (isBipartite(&G)) { printf("二分图\n"); } else { printf("不是二分图\n"); } return 0; } ``` ##### 关键实现细节说明 - **邻接表结构**:使用 `AGraph` 定义(与引用[4]一致)。每个顶点对应一个链表存储邻居,`ArcNode` 表示边。 - **DFS递归**:`dfs` 函数递归着色邻居,参数 `c` 是当前顶点颜色(0或1),递归时传递 `1-c` 确保颜色交替。 - **自环与重边处理**: - 自环:在遍历邻居时,如果 `v == u`(自环),则 `color[v] = color[u]` 触发冲突(`color[v] == c` 条件成立),自动返回 `false`。 - 重边:邻接表中可能包含重复边(多条边连接同一对顶点),但颜色检查只依赖顶点颜色,因此重边不影响正确性。 - **时间复杂度**:$O(n + m)$,每个顶点和边仅访问一次。 - **空间复杂度**:$O(n)$(颜色数组和递归栈)。 - **鲁棒性**:代码处理不连通、自环、重边等情况。如果规模大($n \geq 10^5$),可改用迭代DFS(栈代替递归)避免栈溢出[^2][^4]。 #### 总结 通过DFS双着色检测,该算法高效判断无向是否为二分图:从任意顶点启动着色,递归检查邻居颜色冲突。自环和重边在过程中自动处理。实际应用包括任务调度(如判定冲突是否可二分)和网络流模[^1][^3]。如果实现中遇到具体问题(如结构优化),可进一步调试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值