当前位置: 首页 > news >正文

数据结构与算法:图论——最短路径

最短路径

先给出一些leetcode算法题,以后遇见了相关题目再往上增加

最短路径的4个常用算法是Floyd、Bellman-Ford、SPFA、Dijkstra。不同应用场景下,应有选择地使用它们:

  • 图的规模小,用Floyd。若边的权值有负数,需要判断负圈。
  • 图的规模大,且边的权值非负,用Dijkstra
  • 图的规模大,且边的权值有负数,用SPFA,需要判断负圈。
结点N、边M边权值选用算法数据结构
n<200允许有负Floyd邻接矩阵
n×m<107允许有负Bellman-Ford邻接表
更大有负SPFA邻接表、前向星
更大无负数Dijkstra邻接表、前向星

2.1、Floyd算法

  • Floyed算法:主要是构建 二维矩阵:dp[i][j] 表示从节点 i 到节点 j 最短距离
  • 初始化矩阵时:有方向性并且同一节点的最短距离为0
//  floyed 算法vector<vector<int>> dp(n + 1, vector<int>(n + 1, INT_MAX / 2));for (auto a : times) {dp[a[0]][a[1]] = a[2];}for (int i = 0; i <= n; i++) {dp[i][i] = 0;}for (int k = 0; k <= n; k++) for (int i = 0; i <= n; i++) for (int j = 0; j <= n; j++) if (dp[i][j] > dp[i][k] + dp[k][j]) dp[i][j] = dp[i][k] + dp[k][j];

1、743. 网络延迟时间

n 个网络节点,标记为 1n

给你一个列表 times,表示信号经过 有向 边的传递时间。 times[i] = (ui, vi, wi),其中 ui 是源节点,vi 是目标节点, wi 是一个信号从源节点传递到目标节点的时间。

现在,从某个节点 K 发出一个信号。需要多久才能使所有节点都收到信号?如果不能使所有节点收到信号,返回 -1

示例 1:

img

输入:times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2
输出:2

示例 2:

输入:times = [[1,2,1]], n = 2, k = 1
输出:1

示例 3:

输入:times = [[1,2,1]], n = 2, k = 2
输出:-1

提示:

  • 1 <= k <= n <= 100
  • 1 <= times.length <= 6000
  • times[i].length == 3
  • 1 <= ui, vi <= n
  • ui != vi
  • 0 <= wi <= 100
  • 所有 (ui, vi) 对都 互不相同(即,不含重复边)
//  floyed 算法
class Solution {
public:int networkDelayTime(vector<vector<int>>& times, int n, int k) {vector<vector<int>> dp(n + 1, vector<int>(n + 1, INT_MAX / 2));for (auto a : times) {dp[a[0]][a[1]] = a[2];}for (int i = 0; i <= n; i++) {dp[i][i] = 0;}for (int k = 0; k <= n; k++) {for (int i = 0; i <= n; i++) {for (int j = 0; j <= n; j++) {if (dp[i][j] > dp[i][k] + dp[k][j]) {dp[i][j] = dp[i][k] + dp[k][j];}}}}int res = 0;for (int i = 1; i <= n; i++) {if (dp[k][i] == INT_MAX / 2)return -1;res = max(res, dp[k][i]);}return res;}
};

2、1334. 阈值距离内邻居最少的城市

  • 这个用floyed直接算即可。无向图构造矩阵时重复操作即可

n 个城市,按从 0n-1 编号。给你一个边数组 edges,其中 edges[i] = [fromi, toi, weighti] 代表 fromitoi 两个城市之间的双向加权边,距离阈值是一个整数 distanceThreshold

返回能通过某些路径到达其他城市数目最少、且路径距离 最大distanceThreshold 的城市。如果有多个这样的城市,则返回编号最大的城市。

注意,连接城市 ij 的路径的距离等于沿该路径的所有边的权重之和。

示例 1:

image-20240508214812051

输入:n = 4, edges = [[0,1,3],[1,2,1],[1,3,4],[2,3,1]], distanceThreshold = 4
输出:3
解释:城市分布图如上。
每个城市阈值距离 distanceThreshold = 4 内的邻居城市分别是:
城市 0 -> [城市 1, 城市 2] 
城市 1 -> [城市 0, 城市 2, 城市 3] 
城市 2 -> [城市 0, 城市 1, 城市 3] 
城市 3 -> [城市 1, 城市 2] 
城市 0 和 3 在阈值距离 4 以内都有 2 个邻居城市,但是我们必须返回城市 3,因为它的编号最大。

示例 2:

image-20240508214822340

输入:n = 5, edges = [[0,1,2],[0,4,8],[1,2,3],[1,4,2],[2,3,1],[3,4,1]], distanceThreshold = 2
输出:0
解释:城市分布图如上。 
每个城市阈值距离 distanceThreshold = 2 内的邻居城市分别是:
城市 0 -> [城市 1] 
城市 1 -> [城市 0, 城市 4] 
城市 2 -> [城市 3, 城市 4] 
城市 3 -> [城市 2, 城市 4]
城市 4 -> [城市 1, 城市 2, 城市 3] 
城市 0 在阈值距离 2 以内只有 1 个邻居城市。
class Solution {
public:int findTheCity(int n, vector<vector<int>>& edges, int distanceThreshold) {vector<vector<int>> dp(n, vector<int>(n, INT_MAX / 2));for (auto a : edges) {dp[a[0]][a[1]] = a[2];dp[a[1]][a[0]] = a[2];}for (int k = 0; k < n; k++)for (int i = 0; i < n; i++)for (int j = 0; j < n; j++)if (dp[i][j] > dp[i][k] + dp[k][j])dp[i][j] = dp[i][k] + dp[k][j];// floyed计算完毕,取次数判断即可vector<int> cnt(n, 0);for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {if (i == j)continue;if (dp[i][j] <= distanceThreshold)cnt[i]++;}}int min = *min_element(cnt.begin(), cnt.end());int res;for (int i = n - 1; i >= 0; i--) {if (min == cnt[i]) {res = i;break;}}return res;}
};

2.2、BellmanFord算法

  • Bellman-ford算法的思路也很简单,直接就是两层循环,内层循环所有边,外层循环就是循环所有边的次数。
  • 时间复杂度是O(n*m)显然不如dijkstra快
  • 优点:它可以处理负权边和负权环的情况。并且可以处理限制次数的问题
//  dp[j] 表示节点k到j的最短路径:并且注意每次更新最短路径,是在上一次的dp上更新:
//  a[0] 表示起始节点;a[1] 表示最终节点;a[2]表示a[0]到a[1] 的距离大小。
//  a[0]->a[1]距离为a[2]:所以每次更新的都是 dp[a[1]] ,但是需要上一次的整体的predp,来取a[0]节点的最短距离// 最标准的形式有前一个的最小距离的predp
int networkDelayTime(vector<vector<int>>& times, int n, int k) {vector<int> dp(n+1,INT_MAX/2);dp[k] = 0;bool flag;while(1){flag = true;vector<int> predp(dp);for(auto a:times){if(dp[a[1]] > predp[a[0]]+a[2]){flag = false;dp[a[1]] = predp[a[0]]+a[2];}}if(flag)	break;}int res = *max_element(dp.begin()+1,dp.end());return res==INT_MAX/2?-1:res;}//	 然而没有predp也可以,省下来空间
int networkDelayTime(vector<vector<int>>& times, int n, int k) {vector<int> dp(n+1,INT_MAX/2);dp[k ] = 0;bool flag;while(1){flag = true;for(auto a:times){if(dp[a[1]] > dp[a[0]]+a[2]){flag = false;dp[a[1]] = dp[a[0]]+a[2];}}if(flag) break;}int res = *max_element(dp.begin()+1,dp.end());return res==INT_MAX/2?-1:res;
}

1、743. 网络延迟时间

示例 1:

img

输入:times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2
输出:2
// BellmanFord算法  算法复杂度为O(m*n)
class Solution {
public:int networkDelayTime(vector<vector<int>>& times, int n, int k) {vector<int> dp(n+1,INT_MAX/2);dp[k ] = 0;bool flag;while(1){flag = true;// vector<int> predp(dp);for(auto a:times){if(dp[a[1]] > dp[a[0]]+a[2]){flag = false;dp[a[1]] = dp[a[0]]+a[2];}}if(flag) break;}int res = *max_element(dp.begin()+1,dp.end());return res==INT_MAX/2?-1:res;}
};

2、787. K 站中转内最便宜的航班

  • 经典使用BellmanFord算法题目最多经过 k 站中转的路线

n 个城市通过一些航班连接。给你一个数组 flights ,其中 flights[i] = [fromi, toi, pricei] ,表示该航班都从城市 fromi 开始,以价格 pricei 抵达 toi

现在给定所有的城市和航班,以及出发城市 src 和目的地 dst,你的任务是找到出一条最多经过 k 站中转的路线,使得从 srcdst价格最便宜 ,并返回该价格。 如果不存在这样的路线,则输出 -1

示例 1:

img

输入: 
n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]]
src = 0, dst = 2, k = 1
输出: 200
解释: 
城市航班图如下
从城市 0 到城市 2 在 1 站中转以内的最便宜价格是 200,如图中红色所示。

示例 2:

img

输入: 
n = 3, edges = [[0,1,100],[1,2,100],[0,2,500]]
src = 0, dst = 2, k = 0
输出: 500
解释: 
城市航班图如下
从城市 0 到城市 2 在 0 站中转以内的最便宜价格是 500,图中蓝色所示。

提示:

  • 1 <= n <= 100
  • 0 <= flights.length <= (n * (n - 1) / 2)
  • flights[i].length == 3
  • 0 <= fromi, toi < n
  • fromi != toi
  • 1 <= pricei <= 104
  • 航班没有重复,且不存在自环
  • 0 <= src, dst, k < n
  • src != dst
/*BellmanFord算法::外层的路径就是中转的次数,但是注意K++;是中转1此,那么可以使用两条路径使用BellmanFord算法最标准形式:使用predp形式
*/
class Solution {
public:int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst, int k) {vector<int> dp(n, 1e5+1);dp[src] = 0;k++;while (k--) {vector<int> predp(dp);// 这里最好加&可以大大提高速度for (auto &a : flights) {if(dp[a[1]]>predp[a[0]]+a[2])dp[a[1]] =predp[a[0]]+a[2];}}return dp[dst] ==  1e5+1? -1 : dp[dst];}
};
/*不使用BellmanFord算法最标准形式:无predp形式无法准确得到中转次数:结果不对,但是不考虑次数的话,也能得到最短距离
*/// 结果不对
class Solution {
public:int findCheapestPrice(int n, vector<vector<int>>& flights, int src, int dst,int k) {vector<int> dp(n, 1e5+1);dp[src] = 0;k++;while (k--) {// vector<int> predp(dp);for (auto &a : flights) {if(dp[a[1]]>dp[a[0]]+a[2])dp[a[1]] =dp[a[0]]+a[2];}}return dp[dst] ==  1e5+1? -1 : dp[dst];}
};

3、1514. 概率最大的路径

  • 本题重点是无向图:两边都要操作一次,重复操作即可
  • 无向图:说白了就是条件是有向图的两倍,给反转前后节点即可

给你一个由 n 个节点(下标从 0 开始)组成的无向加权图,该图由一个描述边的列表组成,其中 edges[i] = [a, b] 表示连接节点 a 和 b 的一条无向边,且该边遍历成功的概率为 succProb[i]

指定两个节点分别作为起点 start 和终点 end ,请你找出从起点到终点成功概率最大的路径,并返回其成功概率。

如果不存在从 startend 的路径,请 返回 0 。只要答案与标准答案的误差不超过 1e-5 ,就会被视作正确答案。

示例 1:

img

输入:n = 3, edges = [[0,1],[1,2],[0,2]], succProb = [0.5,0.5,0.2], start = 0, end = 2
输出:0.25000
解释:从起点到终点有两条路径,其中一条的成功概率为 0.2 ,而另一条为 0.5 * 0.5 = 0.25

示例 2:

img

输入:n = 3, edges = [[0,1],[1,2],[0,2]], succProb = [0.5,0.5,0.3], start = 0, end = 2
输出:0.30000

示例 3:

img

输入:n = 3, edges = [[0,1]], succProb = [0.5], start = 0, end = 2
输出:0.00000
解释:节点 0 和 节点 2 之间不存在路径

提示:

  • 2 <= n <= 10^4
  • 0 <= start, end < n
  • start != end
  • 0 <= a, b < n
  • a != b
  • 0 <= succProb.length == edges.length <= 2*10^4
  • 0 <= succProb[i] <= 1
  • 每两个节点之间最多有一条边
class Solution {
public:double maxProbability(int n, vector<vector<int>>& edges,vector<double>& succProb, int start_node,int end_node) {vector<double> dp(n, 0);dp[start_node] = 1;while (1) {bool flag = true;for (int i = 0; i < succProb.size(); i++) {// 双向图:反转前后再操作一次即可if (dp[edges[i][1]] < dp[edges[i][0]] * succProb[i]) {flag = false;dp[edges[i][1]] = dp[edges[i][0]] * succProb[i];}if (dp[edges[i][0]] < dp[edges[i][1]] * succProb[i]) {flag = false;dp[edges[i][0]] = dp[edges[i][1]] * succProb[i];}}if (flag)   break;}return dp[end_node];}
};

3、1334. 阈值距离内邻居最少的城市

  • 这个用floyed直接算即可。使用bellmanFord可以做

n 个城市,按从 0n-1 编号。给你一个边数组 edges,其中 edges[i] = [fromi, toi, weighti] 代表 fromitoi 两个城市之间的双向加权边,距离阈值是一个整数 distanceThreshold

返回能通过某些路径到达其他城市数目最少、且路径距离 最大distanceThreshold 的城市。如果有多个这样的城市,则返回编号最大的城市。

注意,连接城市 ij 的路径的距离等于沿该路径的所有边的权重之和。

示例 1:

image-20250502234625382

输入:n = 4, edges = [[0,1,3],[1,2,1],[1,3,4],[2,3,1]], distanceThreshold = 4
输出:3
解释:城市分布图如上。
每个城市阈值距离 distanceThreshold = 4 内的邻居城市分别是:
城市 0 -> [城市 1, 城市 2] 
城市 1 -> [城市 0, 城市 2, 城市 3] 
城市 2 -> [城市 0, 城市 1, 城市 3] 
城市 3 -> [城市 1, 城市 2] 
城市 0 和 3 在阈值距离 4 以内都有 2 个邻居城市,但是我们必须返回城市 3,因为它的编号最大。

示例 2:

image-20250502234614892

输入:n = 5, edges = [[0,1,2],[0,4,8],[1,2,3],[1,4,2],[2,3,1],[3,4,1]], distanceThreshold = 2
输出:0
解释:城市分布图如上。 
每个城市阈值距离 distanceThreshold = 2 内的邻居城市分别是:
城市 0 -> [城市 1] 
城市 1 -> [城市 0, 城市 4] 
城市 2 -> [城市 3, 城市 4] 
城市 3 -> [城市 2, 城市 4]
城市 4 -> [城市 1, 城市 2, 城市 3] 
城市 0 在阈值距离 2 以内只有 1 个邻居城市。
class Solution {
public:int targetnum(int n, vector<vector<int>>& edges, int distanceThreshold,int k) {vector<int> dp(n, INT_MAX / 2);dp[k] = 0;while (1) {bool flag = true;vector<int> predp(dp);for (auto& a : edges) {if (dp[a[1]] > predp[a[0]] + a[2]) {flag = false;dp[a[1]] = predp[a[0]] + a[2];}if (dp[a[0]] > predp[a[1]] + a[2]) {flag = false;dp[a[0]] = predp[a[1]] + a[2];}}if (flag)break;}int res = 0;/*这里注意:这个是排除本身for (int i = 0; i < n; i++) {if (i == k)continue;if (dp[i] <= distanceThreshold) {res++;}}若改成:只要碰到i!=k,则跳出这个for循环,后面都不执行了for (int i = 0; i < n && i!=k; i++) {if (dp[i] <= distanceThreshold) {res++;}}*/for (int i = 0; i < n; i++) {if (i == k)continue;if (dp[i] <= distanceThreshold) {res++;}}return res;}// 找到最右边的最小值及坐标。int findTheCity(int n, vector<vector<int>>& edges, int distanceThreshold) {int min_num = 200;int res = 0;for(int i = 0;i<n;i++){int mid = BellmabFord( n, edges, i, distanceThreshold);if(mid<=min_num){min_num = mid;res = i; }}return res;}// 直观但臃肿。int findTheCity(int n, vector<vector<int>>& edges, int distanceThreshold) {int minn = INT_MAX / 2;vector<int> res;for (int i = 0; i < n; i++) {res.push_back(targetnum(n, edges, distanceThreshold, i));}int sul = 0;int minnub = *min_element(res.begin(), res.end());for (int i = n - 1; i >= 0; i--) {if (res[i] == minnub) {sul = i;break;}}return sul;}
};

2.3、dijkstra算法

  • 基础型:图的规模大,且边的权值非负,用Dijkstra时间复杂度O(N*N)。可以看出时间复杂度 只和 n (节点数量)有关系。
// dijkstra算法基础版/*基础版:适用于题目中给出距离矩阵,给出矩阵
*/
vector<int> dijkstra(vector<vector<int>>& value, int start) {//需要一个二维矩阵从0到n,0基本上没有用,无关的都是INT_MAX / 2//对角线为0//返回了一个value[i][j]表示从i到j的最短路径,但是i,j不为0int len = value.size();      // len = n + 1;int n = len - 1;vector<int> res(len, INT_MAX);res[start] = 0;vector<bool> visit(len, false);for (int i = 1; i <= n; i++) {// 找到最小蓝的位置int minbule = 0;for (int j = 1; j <= n; j++) {if (!visit[j] && res[minbule] > res[j]) {minbule = j;}}if(visited[blue]) continue;// 把最小蓝变成白色visit[minbule] = true;// 更新所有最短距离for (int j = 1; j <= n; j++) {res[j] = min(res[j], res[minbule] + value[minbule][j]);}}return res;
}
  • 堆优化型:使用边数,边数少的,堆优化比较好。时间复杂度:O(E * (N + logE)) E为边的数量,N为节点数量。
  • 适用条件:但 n 很大,边 的数量 很小的时候(稀疏图),是不是可以换成从边的角度来求最短路呢?
int dijkstra_networkDelayTime2(vector<vector<int>>& times, int n, int k) {unordered_map<int, vector<pair<int, int > > > mp;for (auto a : times) {mp[a[0]].push_back({a[1], a[2]});}// 不一定要用map,使用vector效果一样:只不过是保存a[0]点指向的节点和距离vector<vector<pair<int, int>>> g(n);for (auto &t : times) {int x = t[0] - 1, y = t[1] - 1;g[x].emplace_back(y, t[2]);}作者:力扣官方题解
链接:https://leetcode.cn/problems/network-delay-time/solutions/909575/wang-luo-yan-chi-shi-jian-by-leetcode-so-6phc/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。vector<int> dismin(n + 1, INT_MAX / 2);vector<bool> visited(n + 1, false);dismin[k] = 0;// 优先队列<蓝点的最短距离,蓝点坐标>小顶堆priority_queue< pair<int, int>, vector<pair<int, int> >,  greater<>  > que;que.push({0, k});while (!que.empty()) {int minblue = que.top().second;que.pop();// 变成白点if (visited[minblue]) continue;visited[minblue] = true;// 增加这个白点会有什么影响对于 dismin// 遍历所有与新白点连接的蓝点for (pair<int, int > a : mp[minblue]) {if (!visited[a.first] && dismin[a.first] > a.second + dismin[minblue] ) {dismin[a.first] = a.second + dismin[minblue];que.push({dismin[a.first], a.first});}}}int res = *max_element(dismin.begin() + 1, dismin.end());return res == INT_MAX / 2 ? -1 : res;
}
  • 时间复杂度:O(E * (N + logE)) E为边的数量,N为节点数量

  • 空间复杂度:O(log(N^2))

  • while (!pq.empty()) 时间复杂度为 E ,while 里面 每次取元素 时间复杂度 为 logE,和 一个for循环 时间复杂度 为 N 。所以整体是 E * (N + logE)

  • sort排序与大顶堆

    • 优先队列
    • less<>表示从上到下是递减的
    • greater<>表示从上到下是递增的
    #include <bits/stdc.h>
    using namespace std;// priority_queue
    // less<>表示从上到下是递减的
    // greater<>表示从上到下是递增的
    // 默认  不加默认less<>   大顶堆就是less<> 
    // 如果想要头上最小需要加上greater<>
    void prio_int() {vector<int> strs = {5,8,2,6,1,8,2};priority_queue<int, vector<int>, less<>> que(strs.begin(),strs.end());while(que.empty()==0){cout<<que.top()<<endl;que.pop();}return;
    }// 优先队列的自定义
    // 优先队列与传统sort的相反
    void prio_string() {vector<string> strs = {"xhh", "mmcy", "mi", "xhz", "abcdef"};struct cmp{bool operator()(string a,string b){return a.size()<b.size()||(a.size()==b.size() && a>b);}};priority_queue<string, vector<string>, cmp> que(strs.begin(),strs.end());while(que.empty()==0){cout<<que.top()<<endl;que.pop();}return;
    }// map自动排序,unordered_map 不排序,想排序直接用
    // vector<pair<int,string>>来重新装一下,再排序
    void sort_map_int() {map<int, string> mp = {{1, "ab"}, {8, "zx"}, {5, "ac"}, {4, "ae"}};for (auto a : mp) {cout << a.first << "->" << a.second << endl;}return ;
    }// sort pair使用 a.first   a.second
    // 类型使用auto肯定是对的,但是可能没有提示first、second
    void sort_pair_int() {vector<pair<int, string>> test_vector = {{5, "abc"}, {1, "ac"}, {1, "ad"}, {2, "ac"}};sort(test_vector.begin(), test_vector.end(), [](auto a, auto b) {return (a.first > b.first || (a.first == b.first && a.second > b.second));});for (auto a : test_vector ) {cout << a.first << "->" << a.second << endl;}return ;
    }void sort_vector_int() {vector<int> test_vector = {5, 4, 9, 7};sort(test_vector.begin(), test_vector.end(), [](auto a, auto b) {return a > b;});for (auto a : test_vector ) {cout << a << " ";}cout << endl;return ;
    }void sort_vector_vector_int() {vector<vector<int>> test_vector = {{1, 2}, {9, 8}, {1, 3}, {8, 2}, {6, 5}};sort(test_vector.begin(), test_vector.end(), [](auto a, auto b) {return (a[0] < b[0] || (a[0] == b[0] && a[1] < b[1]));});for (auto a : test_vector ) {for (auto b : a) {cout << b << " ";}cout << endl;}return ;
    }int main() {sort_vector_int();cout << "****************" << endl;sort_vector_vector_int();cout << "****************" << endl;sort_pair_int();cout << "****************" << endl;sort_map_int();cout << "****************" << endl;prio_string();cout << "****************" << endl;prio_int();
    }
    

1、743. 网络延迟时间

n 个网络节点,标记为 1n

给你一个列表 times,表示信号经过 有向 边的传递时间。 times[i] = (ui, vi, wi),其中 ui 是源节点,vi 是目标节点, wi 是一个信号从源节点传递到目标节点的时间。

现在,从某个节点 K 发出一个信号。需要多久才能使所有节点都收到信号?如果不能使所有节点收到信号,返回 -1

示例 1:

image-20250502234548722

输入:times = [[2,1,1],[2,3,1],[3,4,1]], n = 4, k = 2
输出:2

示例 2:

输入:times = [[1,2,1]], n = 2, k = 1
输出:1

示例 3:

输入:times = [[1,2,1]], n = 2, k = 2
输出:-1

提示:

  • 1 <= k <= n <= 100
  • 1 <= times.length <= 6000
  • times[i].length == 3
  • 1 <= ui, vi <= n
  • ui != vi
  • 0 <= wi <= 100
  • 所有 (ui, vi) 对都 互不相同(即,不含重复边)
/*普通版本
*/class Solution {
public:int networkDelayTime(vector<vector<int>>& times, int n, int k) {vector<int> dp(n + 1, INT_MAX / 2);dp[k] = 0;vector<vector<int>> dis(n + 1, vector<int>(n + 1, INT_MAX / 2));for (auto& a : times) {dis[a[0]][a[1]] = a[2];}vector<int> visited(n + 1, false);//for(int i = 0;i<=n;i++){while(1) {int blue = 0;for (int i = 0; i <= n; i++) {if (!visited[i] && dp[blue] > dp[i]) {blue = i;}}// 再次遇到说明最小值就是0了,结束了if(visited[blue]) break;visited[blue] = true;for (int i = 0; i <= n; i++) {if (dp[i] > dp[blue] + dis[blue][i]) {dp[i] = dp[blue] + dis[blue][i];}}}int res = *max_element(dp.begin() + 1, dp.end());return res == INT_MAX / 2 ? -1 : res;}
};// 堆优化版本
class Solution {
public:int networkDelayTime(vector<vector<int>>& times, int n, int k) {priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> que;//	que.push({k,0});que.push({0, k});vector<bool> visited(n + 1, false);vector<int> dp(n + 1, INT_MAX / 2);dp[k] = 0;while (!que.empty()) {auto blue = que.top();que.pop();// 这里不用想那么多:看见置true直接在前面加判断if( visited[blue.second]) continue;visited[blue.second] = true;for (auto& a : times) {// 这里直接取头节点不是这个blue的直接跳过,已经为白的直接跳过// 目的是为了取最小的蓝if (a[0] != blue.second || visited[a[1]] )continue;if (dp[a[1]] > dp[blue.second] + a[2]) {dp[a[1]] = dp[blue.second] + a[2];que.push({dp[a[1]], a[1]});}}}int res = *max_element(dp.begin() + 1, dp.end());return res == INT_MAX / 2 ? -1 : res;}
};

2、1334. 阈值距离内邻居最少的城市

  • 直接使用堆优化:注意双向图即可

n 个城市,按从 0n-1 编号。给你一个边数组 edges,其中 edges[i] = [fromi, toi, weighti] 代表 fromitoi 两个城市之间的双向加权边,距离阈值是一个整数 distanceThreshold

返回能通过某些路径到达其他城市数目最少、且路径距离 最大distanceThreshold 的城市。如果有多个这样的城市,则返回编号最大的城市。

注意,连接城市 ij 的路径的距离等于沿该路径的所有边的权重之和。

示例 1:

image-20250502234526613

输入:n = 4, edges = [[0,1,3],[1,2,1],[1,3,4],[2,3,1]], distanceThreshold = 4
输出:3
解释:城市分布图如上。
每个城市阈值距离 distanceThreshold = 4 内的邻居城市分别是:
城市 0 -> [城市 1, 城市 2] 
城市 1 -> [城市 0, 城市 2, 城市 3] 
城市 2 -> [城市 0, 城市 1, 城市 3] 
城市 3 -> [城市 1, 城市 2] 
城市 0 和 3 在阈值距离 4 以内都有 2 个邻居城市,但是我们必须返回城市 3,因为它的编号最大。

示例 2:

image-20250502234509711

输入:n = 5, edges = [[0,1,2],[0,4,8],[1,2,3],[1,4,2],[2,3,1],[3,4,1]], distanceThreshold = 2
输出:0
解释:城市分布图如上。 
每个城市阈值距离 distanceThreshold = 2 内的邻居城市分别是:
城市 0 -> [城市 1] 
城市 1 -> [城市 0, 城市 4] 
城市 2 -> [城市 3, 城市 4] 
城市 3 -> [城市 2, 城市 4]
城市 4 -> [城市 1, 城市 2, 城市 3] 
城市 0 在阈值距离 2 以内只有 1 个邻居城市。
/*无向图的堆优化djikstra算法:
*/
class Solution {
public:int target(int n, vector<vector<int>>& edges, int distanceThreshold,int k) {priority_queue<pair<int, int>, vector<pair<int, int>>, greater<>> que;que.push({0, k});vector<int> dis(n, INT_MAX / 2);dis[k] = 0;vector<bool> visited(n, false);while (!que.empty()) {int blue = que.top().second;que.pop();if (visited[blue])continue;visited[blue] = true;for (auto& a : edges) {if (a[0]==blue && dis[a[1]] > dis[a[0]] + a[2]) {dis[a[1]] = dis[a[0]] + a[2];que.push({dis[a[1]], a[1]});}if (a[1]==blue && dis[a[0]] > dis[a[1]] + a[2]) {dis[a[0]] = dis[a[1]] + a[2];que.push({dis[a[0]], a[0]});}}}int res = 0;for (auto& a : dis) {if (a <= distanceThreshold)res++;}return res;}int findTheCity(int n, vector<vector<int>>& edges, int distanceThreshold) {int res = INT_MAX / 2;int resdex = 0;for (int i = 0; i < n; i++) {int mid = target(n, edges, distanceThreshold, i);if (mid <= res) {res = mid;resdex = i;}}return  resdex;}
};

相关文章:

数据结构与算法:图论——最短路径

最短路径 先给出一些leetcode算法题&#xff0c;以后遇见了相关题目再往上增加 最短路径的4个常用算法是Floyd、Bellman-Ford、SPFA、Dijkstra。不同应用场景下&#xff0c;应有选择地使用它们&#xff1a; 图的规模小&#xff0c;用Floyd。若边的权值有负数&#xff0c;需要…...

双指针(5)——有效三角形个数

题目&#xff1a; 这道题我们首先可能会想到暴力解法&#xff0c;三个for循环然后进行check&#xff08;&#xff09;。时间复杂度肯定是不允许的。 同时&#xff0c;验证可以组成三角形的条件是任意两边之和大于第三边&#xff0c;这就意味着我们每组要进行三次比较。但也有捷…...

Qt QGraphicsScene 的用法

背景&#xff0c;为什么要写这篇博客 今天学习 model - view 模式的时候还看到有 scene - view 模式。不知道还有这个模式&#xff0c;所以学习了下。 学习后总体的感觉是&#xff1a;其实没有也是可以的&#xff0c;但有了方便许多。 从两种画图的方法开始说 以前有个项目也…...

使用 Tesseract 实现藏文OCR

要识别藏文&#xff0c;最常用且有效的方法是使用Tesseract OCR&#xff08;谷歌开源的OCR工具&#xff09;&#xff0c;因为它拥有针对藏文的预训练模型支持。 &#x1f680; 一、安装 Tesseract OCR 软件&#xff1a; 下载链接&#xff1a;Tesseract OCR 下载页面 Windows用…...

数字智慧方案5873丨智慧交通设计方案(57页PPT)(文末有下载方式)

资料解读&#xff1a;智慧交通设计方案 详细资料请看本解读文章的最后内容。 智慧交通设计方案是一份详尽的交通规划文件&#xff0c;旨在通过科学的交通设计方法&#xff0c;优化交通系统&#xff0c;提升交通效率&#xff0c;确保交通安全&#xff0c;并促进可持续发展。该…...

【quantity】6 温度单位实现(temperature.rs)

一源码 以下代码实现了一个温度单位系统&#xff0c;支持开尔文(Kelvin)和摄氏度(Celsius)之间的转换和运算。 /// Temperature (kelvin) / 温度 (开尔文) use super::{Quantity, prefix::*}; use crate::unit::Kelvin; use derive_more::{Add, Sub, AddAssign, SubAssign};/…...

ARConv的复现流程

使用环境 Python 3.10.16 torch 2.1.1cu118 torchvision 0.16.1cu118 其它按照官方提供代码的requirements.txt安装 GitHub - WangXueyang-uestc/ARConv: Official repo for Adaptive Rectangular Convolution 数据准备 从官方主页下载pancollection数据集PanCollection…...

安卓游戏APK文件解密与编辑的完整攻略

在移动游戏开发中,保护游戏数据不被篡改是开发者的重要任务。然而,随着逆向工程技术的发展,破解游戏数据也变得可能。本文将详细介绍如何分析、解密和编辑APK安装包中的加密JSON文件,特别关注assets/task目录下的文件,并提供一种绕过checkfile.json中MD5校验的有效方法。通…...

JVM——JVM 是如何执行方法调用的?

JVM 是如何执行方法调用的&#xff1f; 在 Java 世界的底层运作中&#xff0c;方法调用机制是理解 Java 虚拟机&#xff08;JVM&#xff09;行为的关键之一。JVM 作为 Java 程序运行的核心&#xff0c;承担着执行字节码、管理内存、调度线程等多项职责。而方法调用作为程序逻辑…...

一天学完JDBC!!(万字总结)

文章目录 JDBC是什么 1、环境搭建 && 入门案例2、核心API理解①、注册驱动(Driver类)②、Connection③、statement(sql注入)④、PreparedStatement⑤、ResultSet 3、jdbc扩展(ORM、批量操作)①、实体类和ORM②、批量操作 4. 连接池①、常用连接池②、Durid连接池③、Hi…...

【愚公系列】《Manus极简入门》011-习惯养成教练:“习惯塑造师”

&#x1f31f;【技术大咖愚公搬代码&#xff1a;全栈专家的成长之路&#xff0c;你关注的宝藏博主在这里&#xff01;】&#x1f31f; &#x1f4e3;开发者圈持续输出高质量干货的"愚公精神"践行者——全网百万开发者都在追更的顶级技术博主&#xff01; &#x1f…...

精益数据分析(38/126):SaaS模式的流失率计算优化与定价策略案例

精益数据分析&#xff08;38/126&#xff09;&#xff1a;SaaS模式的流失率计算优化与定价策略案例 在创业和数据分析的领域中&#xff0c;我们不断探索如何更精准地把握业务发展的关键要素。今天&#xff0c;带着与大家共同进步的想法&#xff0c;深入研读《精益数据分析》&a…...

50.【必备】二分答案法与相关题目

本文的网课内容学习自B站左程云老师的算法详解课程&#xff0c;旨在对其中的知识进行整理和分享~ 网课链接&#xff1a;算法讲解051【必备】二分答案法与相关题目_哔哩哔哩_bilibili 一.爱吃香蕉的珂珂 题目&#xff1a;爱吃香蕉的珂珂 算法原理 整体思路 这是一个二分查找算法…...

C# 方法(局部变量和局部常量)

本章内容: 方法的结构 方法体内部的代码执行 局部变量 局部常量 控制流 方法调用 返回值 返回语句和void方法 局部函数 参数 值参数 引用参数 引用类型作为值参数和引用参数 输出参数 参数数组 参数类型总结 方法重载 命名参数 可选参数 栈帧 递归 局部变量 和第5章介绍的字段…...

MQTT 协议与 HTTP 协议的区别

在现代的网络通信中&#xff0c;MQTT 协议和 HTTP 协议都扮演着重要的角色&#xff0c;但它们有着不同的特点和适用场景。下面我们就从多个方面来详细探讨它们之间的区别。 一.协议设计理念 1. MQTT 协议 MQTT&#xff08;Message Queuing Telemetry Transport&#xff09;即…...

博弈论思维——AI与思维模型【90】

一、定义 博弈论思维模型是一种研究在相互影响的决策情境中&#xff0c;参与者如何通过策略选择来实现自身利益最大化的理论框架。它分析参与者之间的相互作用、策略组合以及由此产生的结果&#xff0c;帮助人们理解在竞争或合作环境下的决策逻辑和行为模式。 二、由来 博弈…...

【Bootstrap V4系列】学习入门教程之 表格(Tables)和画像(Figure)

Bootstrap V4系列 学习入门教程之 表格&#xff08;Tables&#xff09;和画像&#xff08;Figure&#xff09; 表格&#xff08;Tables&#xff09;一、Examples二、Table head options 表格头选项三、Striped rows 条纹行四、Bordered table 带边框的表格五、Borderless table…...

第 3 篇:有序的世界:有序表 (TreeMap/TreeSet) 的概念与优势

上一篇我们探讨了哈希表如何以牺牲顺序为代价换取极致的平均速度。然而&#xff0c;在现实世界的许多应用中&#xff0c;数据的有序性不仅是锦上添花&#xff0c;甚至是核心需求。想象一下&#xff1a; 你需要显示一个按价格排序的商品列表。你需要找到某个时间点之前或之后的…...

VulnHub-DC-2靶机

主机发现 sudo arp-scan -l 以sudo管理员权限扫描本地活动ip地址 Interface: eth0, type: EN10MB, MAC: 08:00:27:22:46:4f, IPv4: 192.168.252.230 Starting arp-scan 1.10.0 with 256 hosts (https://github.com/royhills/arp-scan) 192.168.252.6 4c:5f:70:74:3c:3b …...

论文笔记(八十三)STACKGEN: Generating Stable Structures from Silhouettes via Diffusion

STACKGEN: Generating Stable Structures from Silhouettes via Diffusion 文章概括摘要I. INTRODUCTIONII. 相关工作A. 从直觉物理学学习稳定性B. 用于姿态生成的扩散模型C. 自动化顺序装配 III. 方法A. 用于 S E ( 3 ) SE(3) SE(3)积木姿态生成的扩散模型B. 模型架构C. 数据生…...

论文阅读笔记——TesserAct: Learning 4D Embodied World Models

TesserAct 论文 采用RGB-DN&#xff08;RGB深度法线&#xff09; 作为 4D 场景中间表示&#xff0c;由此建模 4D 场景&#xff0c;比纯 2D 视频更准确地建模 3D 几何结构。相比现有的 4D 视频生成&#xff0c;优化速度快&#xff0c;收敛好&#xff0c;且首次从当前帧和文本描述…...

变转速振动信号分析处理与故障诊断算法模块

变转速振动信号分析处理与故障诊断算法模块&#xff0c;作为信号处理算法工具箱的主要功能模块&#xff0c;形成了以变转速振动信号分析处理与故障诊断算法模块的经典算法模型&#xff0c;可应用于各类关键机械部件&#xff08;轴承、齿轮、转子等&#xff09;的信号分析、故障…...

每日算法-250502

每日算法 - 2025.05.02 记录一下今天刷的几道 LeetCode 算法题。 3191. 使二进制数组全部等于 1 的最少操作次数 I 题目 思路 贪心 解题过程 遍历数组 nums。当我们遇到 nums[i] 时&#xff1a; 如果 nums[i] 是 1&#xff0c;我们不需要进行操作&#xff0c;因为目标是全 …...

如何在纯C中实现类、继承和多态(小白友好版)

基本实现原理 /* 通过结构体函数指针模拟类 */ typedef struct {// 成员变量int x; // 成员方法&#xff08;函数指针&#xff09; void (*print)(void* self); } MyClass;/* 成员函数实现 */ void my_print(void* self) {MyClass* obj (MyClass*)self;p…...

AE/PR插件 转场创建大师专业版 Transition Master Pro v2.0.2 Win+使用教程

Transition Master Pro v2.0.2是一款原生转场插件&#xff0c;专为Adobe Premiere Pro和After Effects设计。它提供了创建、导出和销售自己的转场效果&#xff0c;或从一个庞大的转场预设库中选择。使用Transition Master Pro v2.0.2&#xff0c;您可以快速轻松地创建令人惊叹的…...

[Linux]从零开始的STM32MP157 Buildroot根文件系统构建

一、前言 在前面的教程中&#xff0c;教了大家如何移植一个LInux的内核并且正确启动&#xff0c;我们发现Linux内核在启动后会出现一个错误&#xff0c;提示我们没有找到根文件系统。那么什么是根文件系统呢&#xff1f;之前我们使用Ubuntu编译了STM32MP157的TF-A,UBOOT,LINUX内…...

阿里云服务器 篇五(加更):短链服务网站:添加反垃圾邮件功能

文章目录 系列文章(可选)更新YOURLS版本安装 Compliance 插件安装 Phishtank-2.0 插件(可选)安装 httpBL 插件样例网站(不推荐)使用谷歌解决方案更多系列文章 阿里云服务器 篇一:申请和初始化 阿里云服务器 篇二:搭建静态网站 阿里云服务器 篇三:提交搜索引擎收录 阿…...

状压 DP 详解

文章目录 简介做法洛谷 P1171 简介 状压 DP 其实约等于一个 DP 的小技巧&#xff0c;一般应用在处理一个或多个集合的问题中&#xff08;因为状压 DP 的下标就是一个集合&#xff09;&#xff0c;而且在 n n n 太大的时候建议不要使用这种方法。&#xff08;如果你不懂&#…...

多模态大模型轻量化探索-视觉大模型SAM(Segment Anything Model)

往期&#xff0c;笔者基于LLava的数据对齐训练&#xff0c;搞了一个Reyes多模态大模型&#xff0c;并且看了些多模态大模型&#xff0c;相关开源的多模态大模型如&#xff1a;KimiVL、Internvl、QwenVL等&#xff0c;其视觉编码器的尺寸都比较大&#xff0c;如&#xff1a;Moon…...

数据分析_问题/优化

1 报表开发 1.1 数据问题 (1) 数据易错 问题描述 ①数据整合困难:数据来源多样、格式差异大,整合时处理不当易丢错数据. ②计算逻辑复杂:开发人员对复杂计算逻辑的理解产生偏差,会导致计算结果不准. 解决方案 ①建立数据标准,统一修正字段命名、数据类型、日期格式等 ②加强…...

我的stm32驱动电机驱动着突然就卡死程序死机了是为什么

电源不稳定或干扰 电机启动电流冲击&#xff1a;电机运行时可能导致电源电压跌落&#xff0c;影响STM32稳定性。需检查电源滤波电容、使用独立电源或增加稳压模块 地线干扰&#xff1a;电机与MCU共地时&#xff0c;高频噪声可能通过地线耦合&#xff0c;需采用隔离电路或磁耦芯…...

使用 Java 实现一个简单且高效的任务调度框架

目录 一、任务调度系统概述 &#xff08;一&#xff09;任务调度的目标 &#xff08;二&#xff09;任务调度框架的关键组成 二、任务状态设计 &#xff08;一&#xff09;任务状态流转设计 &#xff08;二&#xff09;任务表设计&#xff08;SQL&#xff09; 三、单机任…...

Git 完整教程:初学者分步指南

大家好&#xff0c;这里是架构资源栈&#xff01;点击上方关注&#xff0c;添加“星标”&#xff0c;一起学习大厂前沿架构&#xff01; Git 是一个分布式版本控制系统&#xff0c;可以帮助开发人员跟踪代码更改、与他人协作以及高效管理软件项目。无论您是初学者还是正在提升…...

数字智慧方案5856丨智慧环保综合解决方案(50页PPT)(文末有下载方式)

资料解读&#xff1a;智慧环保综合解决方案 详细资料请看本解读文章的最后内容。 随着城市化进程的加速和环境问题的日益严峻&#xff0c;智慧环保成为提升城市环境管理水平的重要手段。本文将对智慧环保综合解决方案进行详细解读&#xff0c;探讨其在实际应用中的需求、解决…...

VBA快速合并多列单元格

实例需求&#xff1a;工作表中第3行到第5行有如下图所示的数据表&#xff0c;为了方便展示&#xff0c;隐藏了部分列&#xff0c;实际数据为从C列到DO列。 现需要合并第3行和第4行相同内容的单元格&#xff0c;如第10行到第12行所示。 示例代码如下。 Sub MergeDemo()Dim dicM…...

区块链+IoT:创新场景落地背后的技术攻坚战

物联网&#xff08;IoT&#xff09;与区块链技术作为两大颠覆性技术&#xff0c;正通过深度融合推动各行各业的数字化转型。物联网通过连接海量设备实现数据互通与智能化管理&#xff0c;而区块链凭借去中心化、不可篡改和可追溯的特性&#xff0c;为物联网的安全性、隐私保护和…...

自动化测试项目2 --- 比特纵横 [软件测试实战 Java 篇]

目录 项目介绍 项目源码 库地址 项目功能测试 1. 自动化实施步骤 1.1 编写测试用例 1.2 自动化测试脚本开发 1.2.1 配置相关环境, 添加依赖 1.2.2 代码编写 2. 编写自动化脚本过程问题总结 2.1 Actons 方法的使用 2.2 等待的使用 2.3 页面操作 项目性能测试 1. 进…...

【学习笔记】深入理解Java虚拟机学习笔记——第1章 走进Java

第1章 走进Java 1.1 概述 Java成功的原因 1>一次编写到处运行 2>内存管理安全&#xff0c;自动回收 3>运行时编译 4>强大成熟的第三方库 1.2 Java技术体系 1>Java技术体系组成&#xff1a; -Java语言 -Java虚拟机实现 -class文件格式 -Java类库API -第三方J…...

JavaScript性能优化实战之运行时性能优化

在 JavaScript 开发中,运行时性能优化是确保网页响应迅速和流畅的重要环节。优化运行时性能不仅能提高用户体验,还能在高并发的情况下保证应用的稳定性。本文将细化几个常见的 JavaScript 运行时性能优化策略,帮助你提高代码执行效率。 1️⃣ 避免不必要的内存分配和释放 J…...

走进AI的奇妙世界:探索历史、革命与未来机遇

2022年11月30日&#xff0c;ChatGPT的横空出世像一枚深水炸弹&#xff0c;掀起了全球范围的AI狂潮。但这场革命并非偶然——它背后是80年AI发展史的厚积薄发。从图灵的哲学思辨到深度学习的技术突破&#xff0c;再到生成式AI的“涌现”时刻&#xff0c;AI正以惊人的速度模糊人机…...

用c 编写的笔记搜索程序

{XXX文本记录} 文本记录格式 xxx 搜索词条 #include <stdio.h> #include <string.h> #include <stdlib.h>int main(void){FILE *ffopen("help.txt","r");if(fNULL){perror("file");return -1;}char nr[2000];f…...

鼎讯信通 智能通信干扰设备:多频段多模态信号压制解决方案

在万物互联时代&#xff0c;通信安全已成为现代社会的核心基础设施防护重点。面对日益复杂的电磁环境挑战&#xff0c;新一代智能通信干扰设备通过技术创新实现了信号压制能力的革命性突破。本文将深入解析该设备的八大核心功能与技术特性&#xff0c;展现其在商业通信保障、工…...

软件测试概念

这里写目录标题 需求开发模型软件生命周期瀑布模型螺旋模型增量模型、迭代模型敏捷模型Scrum 测试模型V模型W模型&#xff08;双V模型&#xff09; 需求 用户需求&#xff1a;没有经过合理的评估&#xff0c;通常就是一句话 软件需求&#xff1a;是开发人员和测试人员执行工作…...

数据库性能杀手与调优实践

目录 前言一、索引缺失引发的全表扫描灾难1.现象与影响2.优化策略 二、SELECT * 的隐性成本1.危害分析2.优化实践 三、分页查询的性能陷阱1.深度分页问题2.优化方案对比 四、执行计划分析方法论1.关键指标解读2.典型劣化模式识别 五、综合优化最佳实践总结 前言 在数据库应用开…...

初始化列表详解

1.类中包含以下成员&#xff0c;必须放在初始化列表位置进行初始化&#xff1a; 1. 引用成员变量 2.const成员变量 3. 自定义类型成员(且该类没有默认构造函数时 ) 2. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序&#xff0c;与其在初始化列表中的先后次序无关…...

【CVE-2025-1094】:PostgreSQL 14.15 SQL注入漏洞导致的RCE_ 利用代码和分析

目标 PostgreSQL 14.15BeyondTrust Privileged Remote Access (PRA) 和 Remote Support (RS) 软件受影响的版本:使用PostgreSQL 14.15及其版本的BeyondTrust产品Explain CVE-2025-1094 是 PostgreSQL 14.15 版本的 psql 交互式工具中发现的 SQL 注入漏洞。由于输入值的验证不…...

【验证技能】VIP项目大总结

VIP项目快做一段落了&#xff0c;历时一年半&#xff0c;也该要一个大汇总。 VIP简介 VIP开发流程 VIP难点 进程同步 打拍插入不同bit位宽数据问题。 动态升降lane VIP做的不好的地方和改进想法 各层之间交互 testsuite两端关键 所有层的实现架构不统一 VIP经验 ** 架构…...

MyBatis 参数处理全解析

在 Java 开发领域&#xff0c;MyBatis 作为一款优秀的持久层框架&#xff0c;凭借其简洁的设计和强大的功能&#xff0c;受到了广大开发者的青睐。而参数处理作为 MyBatis 中一个至关重要的环节&#xff0c;掌握好它能让我们更高效地使用 MyBatis 进行数据库操作。本文将全面深…...

【自然语言处理与大模型】使用Xtuner进行QLoRA微调实操

本文首先对Xtuner这一微调框架进行简单的介绍。手把手演示如何使用Xtuner对模型进行微调训练&#xff0c;包括数据准备、训练命令执行及训练过程中的监控技巧。最后&#xff0c;在完成微调之后&#xff0c;本文还将介绍如何对微调结果进行简单对话测试。 一、Xtuner微调框架 X…...

2023华为od统一考试B卷【二叉树中序遍历】

前言 博主刷的华为机考题&#xff0c;代码仅供参考&#xff0c;因为没有后台数据&#xff0c;可能有没考虑到的情况 如果感觉对你有帮助&#xff0c;请点点关注点点赞吧&#xff0c;谢谢你&#xff01; 题目描述 思路 0.用Character数组存储树&#xff0c;index下标的左右…...