十度好友

本文探讨了在社交网络中寻找一个人的所有十度好友的方法。通过对比深度优先搜索(DFS)和广度优先搜索(BFS),阐述了BFS算法在解决此类问题上的优势,并提到了Dijkstra算法的应用。

问题:

在社交网络里(比如 LinkedIn),如果A和B是好友,B和C是好友,但是A和C不是好友,那么C是A的二度好友,给定一个社交网络的关系图,如何找到某一个人的所以十度好友。

分析:

如果想找到一个人的十度好友,马上想到的方法应该会是使用深度搜索(DFS)。我们可以从一个点(A),使用深度搜索的方式,当到达第十个点的时候,记录该点并返回到上一层节点,然后继续进行深度搜索,直到A节点的所有邻居节点都已经遍历过了。但是,这种方法有一个潜在的问题,因为从一个点到另一个点,它的路径会有很多条,所以,刚刚通过使用深度搜索的方法会存在一个潜在的问题,就是十度好友可能最后只是三度好友或者五度好友。

其实,我们可以利用BFS的思路,对这个图进行按“层”的搜索。大致思路如下:

1: 把A点放在Queue1 里,设 degree = 0;

2: While (degree != 10 && Queue1.size() != 0)

2.1: 依次遍历Queue 1 里所有的元素,把每一个元素的没有被访问的下一个节点放在Queue 2。 同时把该元素从Queue1里删除。

2.2: 把Queue 2 中所有的元素放在Queue1 里,同时清空 Queue 2。(在 2.1 步里,Queue1 已经为空了。)

2.3:   degree++;

3: 输出Queue1里的所有元素。(Queue1 里包含的一定是十度好友)

这种方法的复杂度是O(|E| + |V|) 。

这个问题的本质也是最短路径问题。对于最短路径问题,最常见的方法莫过于Dijkstra's Algorithm,所以,假设好友和好友的边的长度为 1, 那么我们可以利用Dijkstra's algorithm找出一个点到所有点的最短路径,然后遍历一遍就可以找到十度好友了。此方法的复杂度为O(|E| + |V| log |V|) 。

转载请注明出处:http://blog.youkuaiyun.com/beiyeqingteng

<think> 我们面临的问题是:当入射角为10°时,代码判断发生了全反射,导致无法计算厚度。这是因为原代码中全反射条件判断有误,且折射率计算方法在非垂直入射时存在缺陷。 关键问题分析: 1. 全反射条件判断错误: 原条件:`if n_SiC < n_air * sin(theta_i)` 正确物理条件:当光线从空气(折射率$n_{\text{air}}$)入射到薄膜(折射率$n_{\text{film}}$)时,发生全反射的条件是入射角大于临界角$\theta_c$,其中$\theta_c = \arcsin(n_{\text{air}} / n_{\text{film}})$。因此,判断条件应为: if theta_i > asin(n_air / n_SiC) 注意:这里$\theta_i$是入射角(弧度)。 2. 折射率计算问题: 原代码使用赫尔兹贝格公式(适用于垂直入射)计算折射率,但在非垂直入射时不适用。我们需要一个适用于任意入射角的折射率计算方法。 解决方案: 1. 修正全反射判断条件: 计算临界角,并比较入射角是否大于临界角。 2. 采用适用于任意入射角的折射率计算方法: 利用包络极值比($R_{\max}$和$R_{\min}$)计算折射率,公式如下: $$ s = \sqrt{\frac{R_{\min}}{R_{\max}}} $$ $$ n_{\text{film}} = n_{\text{air}} \sqrt{ \frac{4s}{(1-s)^2} \sin^2\theta_i + \left( \frac{1+s}{1-s} \right)^2 n_{\text{sub}}^2 } $$ 这个公式考虑了入射角$\theta_i$的影响,适用于任意入射角[^3]。 3. 对于垂直入射($\theta_i=0$)的情况,上述公式退化为赫尔兹贝格公式。 修改步骤: 步骤1:在循环外部,我们首先使用垂直入射($\theta_i=0$)的公式估算一个初始折射率,用于后续计算。 步骤2:在循环内部,对于每个入射角,使用上述公式重新计算折射率(因为折射率理论上与入射角无关,但这里我们用不同入射角下的数据来验证,实际计算中也可以只用一个入射角的数据计算折射率)。 步骤3:修正全反射判断条件。 注意:由于我们只有一个入射角(10°)的数据,所以我们需要确保在10°入射角下不发生全反射。如果按照上述公式计算出的折射率$n_{\text{film}}$大于$n_{\text{air}} / \sin(10^\circ)$,则不会全反射。 另外,我们还需要注意:原代码中只有一个角度(10°)被测试,因此修改后需要确保该角度不会跳过。 具体代码修改如下: 1. 折射率计算部分修改: 原代码: R_min_avg = mean(env_min); R_max_avg = mean(env_max); n_SiC = sqrt(n_air^2 + (((1+sqrt(R_min_avg))/(1-sqrt(R_min_avg))) * n_air * n_sub); 修改为(采用任意入射角公式,但需要入射角参数,因此将其移入循环内): 2. 由于公式中需要入射角,因此我们将折射率计算移到循环内部,并且使用每个入射角单独计算(虽然理论上折射率相同,但这样可以利用不同入射角的数据来验证一致性,对于单角度,我们只能计算一次)。 但是,我们注意到,在只有一个入射角数据的情况下,我们只能使用这个入射角来计算折射率。因此,我们先计算初始折射率(用垂直入射公式)作为参考,然后在循环内用该入射角重新计算。 3. 全反射条件修改: critical_angle = asin(n_air / n_SiC); if theta_i > critical_angle warning('角度 %d° 发生全反射,跳过计算', angles(k)); continue; end 然而,对于10°入射角,通常薄膜折射率(如SiC约2.6)大于空气折射率1,临界角约为22.6°(因为$\arcsin(1/2.6)≈22.6°$),所以10°入射角不会发生全反射。因此原代码判断条件错误导致误判。 因此,我们修改全反射判断条件。 4. 还有一个问题:原代码中,在计算折射角时,使用了: sin_theta_r = sin(theta_i) * n_air / n_SiC; cos_theta_r = sqrt(1 - min(sin_theta_r^2, 1)); 这里需要确保$|\sin_theta_r| \leq 1$,否则会出现虚数。所以用min(sin_theta_r^2,1)来约束。 修改后的代码结构: 步骤: 1. 读取数据,预处理(平滑,包络提取)不变。 2. 计算包络的极大值和极小值(注意:这里我们取整个包络线的最大值和最小值,而不是平均) R_min = min(env); % 注意:env是包络线,这里取整个包络的最小值 R_max = max(env); % 整个包络的最大值 3. 设定入射角数组(这里只有一个角度10°) 4. 对于每个入射角: theta_i = 角度转换为弧度 计算s = sqrt(R_min/R_max) 计算折射率n_SiC = n_air * sqrt( (4*s/(1-s)^2)*sin(theta_i)^2 + ((1+s)/(1-s))^2 * n_sub^2 ) 检查全反射条件(如果入射角大于临界角则跳过) 计算折射角:sin_theta_r = n_air * sin(theta_i) / n_SiC 计算cos_theta_r = sqrt(1 - sin_theta_r^2) (注意:取实数部分,不考虑吸收) 计算相邻极值点的波数间隔(方法不变) 计算厚度 注意:由于数据中可能存在多个极值点,我们仍然需要找到所有极值点(极大值和极小值)的位置,然后计算相邻极值点之间的波数间隔的平均值。 另外,由于我们只有一个角度,计算出的厚度就是这个角度下的厚度,不需要多个角度平均。 修改后的代码(关键部分)如下: 由于原代码中角度数组只有一个10°,我们按照上述步骤修改。 完整修改后的代码: ```matlab %% 薄膜厚度计算(动态折射率模型)——修复全反射问题 clear; clc; close all; % 读取数据(请替换为实际数据文件) data = readmatrix('附件1.xlsx'); wavelength = data(:, 1); % 波长数据 (nm) reflectance = data(:, 2); % 反射率数据 angles = 10; % 入射角数组 (度) 只有一个角度10° % 基本参数 n_air = 1.0; % 空气折射率 n_sub = 3.5; % 基底折射率(硅) % 数据预处理 wavenumber = 1e7 ./ wavelength; % 转换为波数(cm⁻¹) smoothed_reflectance = smoothdata(reflectance, 'gaussian', 50); % 高斯平滑 % 希尔伯特变换提取包络 analytic_signal = hilbert(smoothed_reflectance); env = abs(analytic_signal); % 反射率包络 % 计算包络的极值(整个包络的最大值和最小值) R_min = min(env); R_max = max(env); fprintf('包络最小值: %.4f, 最大值: %.4f\n', R_min, R_max); % 计算厚度结果存储 thickness_results = zeros(length(angles), 1); valid_angles = zeros(length(angles), 1); figure; plot(wavelength, reflectance, 'b', 'LineWidth', 1.5); hold on; plot(wavelength, env, 'r--', 'LineWidth', 2); title('反射率数据及包络曲线'); xlabel('波长 (nm)'); ylabel('反射率'); legend('原始数据', '包络曲线'); grid on; for k = 1:length(angles) theta_i = angles(k) * pi / 180; % 入射角(弧度) % 计算s值 s = sqrt(R_min / R_max); % 计算薄膜折射率(任意入射角公式) n_SiC = n_air * sqrt( (4*s/(1-s)^2)*sin(theta_i)^2 + ((1+s)/(1-s))^2 * n_sub^2 ); fprintf('计算得到的薄膜折射率(角度%d°): %.3f\n', angles(k), n_SiC); % 检查全反射(修正条件) critical_angle = asin(n_air / n_SiC); % 临界角(弧度) if theta_i > critical_angle warning('角度 %d° (%.2f弧度) 超过临界角 (%.2f°),跳过计算', ... angles(k), theta_i, critical_angle*180/pi); continue; end % 计算折射角 sin_theta_r = (n_air / n_SiC) * sin(theta_i); cos_theta_r = sqrt(1 - min(sin_theta_r^2, 1)); % 物理约束,取实数部分 % 提取包络的极值点位置(极大值和极小值) [env_max, max_locs] = findpeaks(env, 'MinPeakProminence', 0.01); % 设置合适的峰值突出度 [env_min, min_locs] = findpeaks(-env, 'MinPeakProminence', 0.01); env_min = -env_min; if isempty(env_min) || isempty(env_max) || length(env_min)<2 || length(env_max)<2 error('无法检测到足够干涉极值点'); end % 合并极值点位置(按波长顺序排序) all_locs = sort([min_locs; max_locs]); % 计算相邻极值点之间的波数间隔 wavenumber_at_locs = 1e7 ./ wavelength(all_locs); % 极值点位置的波数 delta_nu = mean(diff(wavenumber_at_locs)); % 相邻极值点波数差的平均值 % 计算厚度(单位:cm,再转换为μm) d_cm = 1 / (2 * n_SiC * cos_theta_r * abs(delta_nu)); % 厚度(cm) d_um = d_cm * 1e4; % 转换为微米 % 存储结果 thickness_results(k) = d_um; valid_angles(k) = angles(k); fprintf('入射角 %d°: 厚度 = %.2f μm\n', angles(k), d_um); end % 移除无效角度结果 thickness_results = thickness_results(valid_angles > 0); valid_angles = valid_angles(valid_angles > 0); % 结果可视化 if ~isempty(valid_angles) figure; bar(valid_angles, thickness_results); title('不同入射角下的薄膜厚度'); xlabel('入射角 (°)'); ylabel('厚度 (μm)'); grid on; % 计算平均厚度(这里只有一个角度,平均即其本身) avg_thickness = mean(thickness_results); fprintf('\n=== 最终结果 ===\n'); fprintf('薄膜平均厚度: %.2f μm\n', avg_thickness); else error('所有角度均发生全反射,无法计算厚度'); end ``` 注意:在提取极值点时,我们使用了`'MinPeakProminence'`参数来避免噪声的干扰,需要根据实际数据调整(这里设为0.01,如果数据噪声大可以适当增大)。 另外,由于我们只有一个入射角,所以循环只执行一次,计算出的厚度就是该角度下的厚度。 这个修改后的代码应该能够解决10°入射角被误判为全反射的问题,并正确计算薄膜厚度。 如果仍然遇到问题,可能需要检查: 1. 包络提取是否正确(通过图形查看) 2. 极值点检测是否足够(图形标注极值点位置) 3. 计算出的折射率是否合理(SiC通常在2.5-3.0之间) 我们可以通过图形标注极值点来验证: 在绘制包络曲线后,添加: ```matlab % 在图上标记极值点 plot(wavelength(all_locs), env(all_locs), 'ko', 'MarkerSize', 8); ``` 相关问题: §§相关问题§§ 1. 如何验证薄膜厚度计算结果的准确性? 2. 当薄膜存在弱吸收时,如何修正厚度计算模型? 3. 椭圆偏振测量技术如何用于薄膜参数测量? </think> 根据您的问题描述,我将修改薄膜厚度计算代码,解决10°入射角全反射问题。关键修改包括全反射条件修正、任意入射角折射率模型和包络提取优化。 ```matlab %% 薄膜厚度计算(增强版) clear; clc; close all; % 读取数据 data = readmatrix('附件1.xlsx'); wavelength = data(:, 1); % 波长数据 (nm) reflectance = data(:, 2); % 反射率数据 angles = 10; % 入射角 (度) % 参数设置 n_air = 1.0; % 空气折射率 n_sub = 3.5; % 基底折射率(硅) % 数据预处理 wavenumber = 1e7 ./ wavelength; % 转换为波数(cm⁻¹) smoothed_reflectance = smoothdata(reflectance, 'gaussian', 30); % 高斯平滑 % 包络提取(改进方法) [upper_env, lower_env] = envelope(smoothed_reflectance, 100, 'peak'); % 内置包络函数 env = (upper_env + lower_env)/2; % 平均包络 % 提取包络极值 [env_max, max_locs] = findpeaks(env, 'MinPeakProminence', 0.01); [env_min, min_locs] = findpeaks(-env, 'MinPeakProminence', 0.01); env_min = -env_min; if isempty(env_min) || isempty(env_max) error('无法检测到足够干涉极值点'); end % 计算极值比 s = sqrt(min(env_min)/max(env_max)); % 极值比 % 计算厚度结果存储 thickness_results = []; valid_angles = []; figure; plot(wavelength, reflectance, 'b', 'LineWidth', 1.5); hold on; plot(wavelength, env, 'r--', 'LineWidth', 2); title('反射率数据及包络曲线'); xlabel('波长 (nm)'); ylabel('反射率'); legend('原始数据', '包络曲线'); grid on; for k = 1:length(angles) theta_i = angles(k) * pi / 180; % 入射角(弧度) % === 关键修改1:任意入射角折射率模型 === n_SiC = n_air * sqrt(... (4*s/(1-s)^2)*sin(theta_i)^2 + ... % 入射角修正项 ((1+s)/(1-s))^2 * n_sub^2 ... % 垂直入射项 ); fprintf('计算得到的薄膜折射率: %.3f\n', n_SiC); % === 关键修改2:全反射条件修正 === critical_angle = asin(n_air / n_SiC); % 临界角(弧度) if theta_i > critical_angle warning('角度 %.1f° 超过临界角(%.1f°),使用垂直入射模型', ... angles(k), critical_angle*180/pi); theta_i = 0; % 回退到垂直入射模型 end % === 关键修改3:折射角计算修正 === sin_theta_r = n_air * sin(theta_i) / n_SiC; cos_theta_r = sqrt(1 - sin_theta_r^2); % 物理约束 % 计算相邻极值点间距 all_locs = sort([min_locs; max_locs]); delta_nu = mean(diff(1e7./wavelength(all_locs))); % 平均波数间隔(cm⁻¹) % 计算厚度 d_cm = 1 / (2 * n_SiC * cos_theta_r * delta_nu); % 厚度(cm) d_um = d_cm * 1e4; % 转换为微米 % 存储结果 thickness_results(end+1) = d_um; valid_angles(end+1) = angles(k); fprintf('入射角 %d°: 厚度 = %.2f μm\n', angles(k), d_um); end % 结果可视化 if ~isempty(valid_angles) figure; bar(valid_angles, thickness_results); title('不同入射角下的薄膜厚度'); xlabel('入射角 (°)'); ylabel('厚度 (μm)'); grid on; % 计算平均厚度 avg_thickness = mean(thickness_results); fprintf('\n=== 最终结果 ===\n'); fprintf('薄膜平均厚度: %.2f μm\n', avg_thickness); else error('所有角度均发生全反射,无法计算厚度'); end ``` ### 关键修改说明: 1. **任意入射角折射率模型**: $$n_{\text{film}} = n_{\text{air}} \sqrt{ \underbrace{\frac{4s}{(1-s)^2}\sin^2\theta_i}_{\text{入射角修正}} + \underbrace{\left(\frac{1+s}{1-s}\right)^2 n_{\text{sub}}^2}_{\text{垂直入射项}} }$$ 其中$s=\sqrt{R_{\min}/R_{\max}}$,适用于任意入射角[^3] 2. **全反射条件修正**: - 使用临界角公式$\theta_c = \arcsin(n_{\text{air}}/n_{\text{film}})$ - 当$\theta_i > \theta_c$时自动回退到垂直入射模型 3. **折射角计算优化**: - 修正折射角计算公式:$\sin\theta_r = \frac{n_{\text{air}}}{n_{\text{film}}} \sin\theta_i$ - 添加物理约束:$\cos\theta_r = \sqrt{1 - \sin^2\theta_r}$ 4. **包络提取改进**: - 使用MATLAB内置`envelope`函数替代Hilbert变换 - 双包络(上/下)联合分析提高精度 - 增强极值点检测(`MinPeakProminence`参数) ### 数学原理验证: 1. **干涉次数与厚度关系**: $$N = \frac{2n d \cos\theta}{\lambda}$$ 其中$N$为干涉条纹数,$d$为膜厚,$\theta$为折射角 2. **波数间隔与厚度**: $$\Delta \nu = \frac{1}{2n d \cos\theta}$$ 其中$\Delta \nu$为相邻极值点波数差(cm⁻¹)[^2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值