旅行商问题的n种解法

问题描述:

旅行商问题(Traveling Salesman Problem,TSP)是旅行商要到若干个城市旅行,各城市之间的费用是已知的,为了节省费用,旅行商决定从所在城市出发,到每个城市旅行一次后返回初始城市,问他应选择什么样的路线才能使所走的总费用最短?此问题可描述如下:设G=(V,E)是一个具有边成本cij的有向图,cij的定义如下,对于所有的i和j,cij>0,若<i,j>不属于E,则cij=∞。令|V|=n,并假设n>1。 G的一条周游路线是包含V中每个结点的一个有向环,周游路线的成本是此路线上所有边的成本和。

问题分析:

旅行商问题要从图G的所有周游路线中求取最小成本的周游路线,而从初始点出发的周游路线一共有(n-1)!条,即等于除初始结点外的n-1个结点的排列数,因此旅行商问题是一个排列问题。排列问题比子集合的选择问题通常要难于求解得多,这是因为n个物体有n!种排列,只有 个子集合(n!>O( ))。通过枚举(n-1)!条周游路线,从中找出一条具有最小成本的周游路线的算法,其计算时间显然为O(n!)。

枚举法思想:程序中采用深度优先策略。(采用隐式和显式两种形式)

枚举算法的特点是算法简单,但运算量大,当问题的规模变大,循环的阶数越大,执行的速度越慢。如果枚举范围太大(一般以不超过两百万次为限),在时间上就难以承受。在解决旅行商问题时,以顶点1为起点和终点,然后求{2…N}的一个全排列,使路程1→{2…N}的一个全排列→1上所有边的权(代价)之和最小。所有可能解由(2,3,4,…,N)的不同排列决定。

核心代码(完整源代码见源代码)

  

为便于讨论,介绍一些关于解空间树结构的术语。在下面分析回溯法和分支限界法时都直接或间接用到解空间树。在解空间树中的每一个结点确定所求问题的一个问题状态(problem state)。由根结点到其它结点的所有路径则确定了这个问题的状态空间(state space)。解状态(solution states)表示一些问题状态S,对于这些问题状态,由根到S的那条路径确定了这解空间中的一个元组。答案状态(answer states)表示一些解状态S,对于这些解状态而言,由根到S的这条路径确定了这问题的一个解(即,它满足隐式约束条件)。解空间的树结构称为状态空间树(state space tree)。

对于旅行商问题,一旦设想出一种状态空间树,那么就可以先系统地生成问题状态,接着确定这些问题状态中的哪些状态是解状态,最后确定哪些解状态是答案状态,从而将问题解出。为了生成问题状态,采用两种根本不同的方法。如果已生成一个结点而它的所有儿子结点还没有全部生成,则这个结点叫做活结点。当前正在生成其儿子结点的活结点叫E-结点。不再进一步扩展或者其儿子结点已全部生成的生成结点就是死结点。在生成问题状态的两种方法中,都要用一张活结点表。在第一种方法中,当前的E-结点R一旦生成一个新的儿子C,这个儿子结点就变成一个新的E-结点,当完全检测了子树C之后,R结点就再次成为E-结点。这相当与问题状态的深度优先生成。在第二种状态生成方法中,一个E-结点一直保持到死结点为止。这两种方法中,将用限界函数去杀死还没有全部生成其儿子结点的那些活结点。如果旅行商问题要求找出全部解,则要生成所有的答案结点。使用限界函数的深度优先结点生成方法称为回溯法。E-结点一直保持到死为止的状态生成方法称为分支限界法

回溯法思想:

       为了应用回溯法,所要求的解必须能表示成一个n- 元组(x1,…,Xn),其中x1是取自某个有穷集Si。通常,所求解的问题需要求取一个使某一规范函数P(x1,…,Xn)取极大值(或取极小值或满足该规范函数条件)的向量。

       假定集合Si的大小是mi,于是就有m=m1m2…Mn个n-元组可能满足函数P。所谓硬性处理是构造这m个n-元组并逐一测试它们是否满足P,从而找出该问题的所有最优解。而回溯法的基本思想是,不断地用修改过的函数Pi(x1,…Xi)(即限界函数)去测试正在构造中的n-元组的部分向量(x1,…,Xi),看其是否可能导致最优解。如果判定(x1,…,Xi)不可能导致最优解,那么就可能要测试的后n-i个元素组成的向量一概略去。因此回溯法作的次数比硬性处理作的测试次数(m次)要少得多。用回溯法求解的旅行商问题,即在枚举法的基础上多了一个约束条件,约束条件可以分为两种类型:显示约束和隐式约束。

核心代码(完整源代码见源代码)

 

分支限界法思想:本题采用FIFO分支限界法。

如前所述,分支限界法是在生成当前E-结点全部儿子之后再生成其它活结点的儿子,且用限界函数帮助避免生成不包含答案结点子树的状态空间的检索方法。在总的原则下,根据对状态控件树中结点检索的次序的不同又将分支限界设计策路分为数种不同的检索方法。在求解旅行商问题时,程序中采用FIFO检索(First In First Out),它的活结点表采用一张先进先出表(即队列)。可以看出,分支限界法在两个方面加速了算法的搜索速度,一是选择要扩展的节点时,总是选择选择一个最小成本的结点,尽可能早的进入最有可能成为最优解的分支;二是扩展节点的过程中,舍弃导致不可行解或导致非最优解的子结点。

核心代码(完整源代码见源代码)

 

贪心法思想:

贪心法是一种改进了的分级处理方法。它首先旅行商问题描述,选取一种度量标准。然后按这种度量标准对n个输入城市排序,并按序一次输入一个城市。如果这个输入和当前已构成在这种量度意义下的部分最优解加在一起不能产生一个可行解,则不把这个城市加入到这部分解中。这种能够得到某种量度意义下的最优解的分级处理方法成为谈心方法。

获得最优路径的贪心法应一条边一条边地构造这棵树。根据某种量度来选择将要计入的下一条边。最简单的量度标准是选择使得迄今为止计入的那些边的成本的和有最小增量的那条边。

核心代码(完整源代码见源代码)

 

源代码:

在程序执行目录下建立data.txt文件,用于存放城市节点信息,格式如下:

5  5

0  7  6  1  3  

7  0  3  7  8 

6  3  0  12 11

1  7  12 0  2

3  8  11 2  0

第一行表示为5行5列,之后为各个节点的权值;

程序执行前先建立如下头文件,用于存储和表示节点信息:

 

[cpp] view plaincopy
  1. //------------------------------------- AdjtwGraph.h文件--------------------------------------------------  
  2. #ifndef AdjTWGraph_H  
  3. #define AdjTWGraph_H  
  4. #include <vector>  
  5. #include <iostream>  
  6. using namespace std;  
  7. const int MaxV=100;  
  8. struct Edge  
  9.  {  
  10.     int dest;  
  11.     int weight;  
  12.     Edge * next;  
  13.      Edge(){}  
  14.      Edge(int d,int w):dest(d),weight(w),next(NULL){}  
  15. };  
  16. struct item  
  17.  {    int data;  
  18.     Edge * adj;  
  19. };  
  20. class AdjTWGraph  
  21.  {  
  22. private:  
  23.     item vertices[MaxV];  
  24.     int numV,numE;  
  25. public :  
  26.     AdjTWGraph();  
  27.     ~AdjTWGraph();  
  28.      int NumV(){return numV;}  
  29.      int NumE(){return numE;}  
  30.     int GetValue(const int i);  
  31.     int GetWeight(const int v1,const int v2);  
  32.     void InsertV(const int & vertex);  
  33.     void InsertE(const int v1,const int v2,int weight);  
  34.     friend ostream& operator<<(ostream& os,  AdjTWGraph & m)  
  35.      {     for (int i = 0; i < m.numV ; i++)     {  
  36.             for (int j = 0; j < m.numV; j++)  
  37.                 os << right << m.GetWeight(i,j) << " ";  
  38.             os << endl;  
  39.         }  
  40.         return os;  
  41.     }  
  42.     friend istream& operator>>(istream& is, AdjTWGraph & m)  
  43.      {    int t;  
  44.         for (int i = 0; i < m.NumV(); i++)  
  45.             for (int j = 0; j < m.NumV(); j++)  
  46.              {  
  47.                 is >> t;     m.InsertE(i,j,t);  
  48.             }  
  49.         return is;  
  50.     }  
  51. };  
  52. AdjTWGraph::AdjTWGraph()  
  53.  {  
  54.     for(int i=0;i<MaxV;i++)     vertices[i].adj=NULL;  
  55.     numV=0;numE=0;  
  56. }  
  57. AdjTWGraph::~AdjTWGraph()  
  58.  {  
  59.     for(int i=0;i<numV;i++)  
  60.      {  
  61.         Edge * p=vertices[i].adj,*q;  
  62.         while(p!=NULL)  
  63.          {  
  64.             q=p->next;delete p;p=q;  
  65.         }  
  66.     }  
  67. }  
  68.  int AdjTWGraph::GetValue(const int i){    return vertices[i].data;  }  
  69. int AdjTWGraph::GetWeight(const int v1,const int v2)  
  70.  {  
  71.     Edge *p=vertices[v1].adj;  
  72.     while(p!=NULL && p->dest<v2) p=p->next;  
  73.      if(v2!=p->dest)    {    return 0;    }  
  74.     return p->weight;  
  75. }  
  76.  void AdjTWGraph::InsertV(const int & v) { vertices[numV].data=v; numV++;  }  
  77. void AdjTWGraph::InsertE(const int v1,const int v2,int weight)  
  78.  {  
  79.     Edge * q=new Edge(v2,weight);  
  80.     if(vertices[v1].adj==NULL) vertices[v1].adj=q;  
  81.     else  
  82.      {  
  83.         Edge *curr=vertices[v1].adj,*pre=NULL;  
  84.          while(curr!=NULL && curr->dest<v2)    {    pre=curr;curr=curr->next;    }  
  85.          if(pre==NULL){    q->next=vertices[v1].adj;vertices[v1].adj=q;        }  
  86.          else    {    q->next=pre->next;pre->next=q;    }  
  87.     }  
  88.     numE++;  
  89. }  
  90. #endif  
  91.   
  92. //------------------------------------- tsp.cpp文件--------------------------------------------------  
  93. #include "AdjtwGraph.h"  
  94. #include <fstream>  
  95. #include <vector>  
  96. #include <algorithm>  
  97. #include <ctime>  
  98. #include <queue>  
  99. using namespace std;  
  100. ofstream fout("out.txt");  
  101. int N;  
  102. AdjTWGraph g;  
  103. struct Node      
  104.  {   int currentIndex;  
  105.     int level;  
  106.     Node * previous;  
  107.      Node(int L = 0, int V = 0, Node *p = NULL):level(L),currentIndex(V), previous(p) {}  
  108. };  
  109. class TspBase  
  110.  {  
  111. protected:      
  112.     vector<int> currentPath;  
  113.     vector<int> bestPath;  
  114.     int cv;  
  115.     int bestV;  
  116.     Node * root;  
  117.   
  118.     int SumV();     
  119.     void EnumImplicit(int k);  
  120.     void BackTrackImplicit(int k);  
  121.   
  122.     void EnumExplicit(Node * r);  
  123.     void BackTrackExplicit(Node * r);  
  124.     void FIFOBB();  
  125.   
  126.     bool Valid(Node *p,int v)  //  
  127.          {    bool flag = true;  
  128.             for(Node *r = p; r->level > 0 && V; r = r->previous)  flag = r->currentIndex !=v;  
  129.             return flag;  
  130.         }  
  131.     void StoreX(Node * p) //  
  132.          {for(Node *r = p; r->level >0 ; r = r->previous )  
  133.  {    currentPath[r->level-1] = r->currentIndex;    }  
  134.         }  
  135.     void Print();  
  136. public:  
  137.      TspBase(){currentPath.resize(N);    bestPath.resize(N);    }  
  138.  ~TspBase(){currentPath.resize(0);bestPath.resize(0);}  
  139.   
  140.     void TspEnumImplicit();  
  141.     void TspBackTrackImplicit();  
  142.   
  143.     void TspEnumExplicit();          
  144.     void TspBackTrackExplicit();  
  145.     
  146.     void TspBB();  
  147.   
  148.     void TspGreedy();       
  149.       
  150.     void DataClear(bool flag)  
  151.      {   currentPath.resize(N);        bestPath.resize(N);  
  152.          if(flag)        { Node * p=root,*q;  
  153.                       while(p!=NULL) {q=p->previous; delete p; p=q;}      
  154.         }  
  155.     }  
  156. };  
  157. void TspBase::TspEnumImplicit()  //         枚举隐式  
  158.  {    fout<<"TspEnumImplicit ..."<<endl;  
  159. cv=0; bestV=10000;  
  160.     for(int i=0;i<N;i++)    currentPath[i]=i;  
  161.     EnumImplicit(1);  
  162.     Print();  
  163. }  
  164. void TspBase::EnumImplicit(int k)  
  165.  {    if(k == N)  
  166.      {    if((cv + g.GetWeight(currentPath[N-1],0)) < bestV)  
  167.          {  
  168.             bestV = cv + g.GetWeight(currentPath[N-1],0);  
  169.             for(int i = 0; i < N; i++)  
  170.               bestPath[i] = currentPath[i];  
  171.         }          
  172.     }  
  173.     else  
  174.         for(int j = k; j < N; j++)  
  175.          {    swap(currentPath[k],currentPath[j]);  
  176.             cv += g.GetWeight(currentPath[k-1],currentPath[k]);  
  177.             EnumImplicit(k+1);  
  178.             cv -= g.GetWeight(currentPath[k-1],currentPath[k]);  
  179.             swap(currentPath[k],currentPath[j]);  
  180.         }  
  181. }  
  182. void TspBase::TspEnumExplicit()    //  枚举显式  
  183.  {   fout<<"TspEnumExplicit  ..."<<endl;  
  184. cv=0;     bestV=10000;  
  185.      for(int i=0;i<N;i++)     currentPath[i]=i;  
  186.      root=new Node(0,-1,NULL);  
  187.      EnumExplicit(root);  
  188.      Print();  
  189. }  
  190.   
  191. void TspBase::EnumExplicit(Node * r)  
  192.  {    if(r->level == N)  
  193.      {    StoreX(r);    cv = SumV();  
  194.         if(cv  < bestV)      
  195.          {    bestV = cv  ;  
  196.             for(int i = 0; i < N; i++)  
  197.               bestPath[i] = currentPath[i];  
  198.         }  
  199.     }  
  200.     else  
  201.         for(int i = 0; i < N; i ++)  
  202.          { if(Valid(r,i))   
  203.              {  Node *q = new Node(r->level+1,i,r);    EnumExplicit(q);    }  
  204.         }  
  205. }  
  206. void TspBase::TspBackTrackImplicit()     //回溯隐式  
  207.  {    fout<<"TspBackTrackImplicit ..."<<endl;  
  208. cv=0;  bestV=10000;  
  209.     for(int i=0;i<N;i++)    currentPath[i]=i;  
  210.     BackTrackImplicit(1);  
  211.     Print();  
  212. }  
  213. void TspBase::BackTrackImplicit(int k)  
  214.  {    if(k == N)  
  215.      {    if((cv + g.GetWeight(currentPath[N-1],0)) < bestV)  
  216.          {  
  217.             bestV = cv + g.GetWeight(currentPath[N-1],0);  
  218.             for(int i = 0; i < N; i++)  
  219.               bestPath[i] = currentPath[i];  
  220.         }          
  221.     }  
  222.     else  
  223.         for(int j = k; j < N; j++)  
  224.          { if((cv + g.GetWeight(currentPath[k-1],currentPath[j])) < bestV)  
  225.            {    swap(currentPath[k],currentPath[j]);  
  226.                cv += g.GetWeight(currentPath[k-1],currentPath[k]);  
  227.             BackTrackImplicit(k+1);  
  228.             cv -= g.GetWeight(currentPath[k-1],currentPath[k]);  
  229.             swap(currentPath[k],currentPath[j]);  
  230.           }  
  231.         }  
  232. }  
  233. void TspBase::TspBackTrackExplicit()      // 回溯显式  
  234.  {    fout<<"TspBackTrackExplicit  ..."<<endl;   
  235. cv=0;     bestV=10000;  
  236.      for(int i=0;i<N;i++)     currentPath[i]=i;  
  237.      root=new Node(0,-1,NULL);  
  238.      BackTrackExplicit(root);  
  239.      Print();  
  240. }  
  241. void TspBase::BackTrackExplicit(Node * r)  
  242.  {    int w=0;  //初值  
  243.     if(r->level == N)  
  244.      {    StoreX(r);  
  245.         cv = SumV();  
  246.         if(cv  < bestV)      
  247.          {   bestV = cv  ;  
  248.             for(int i = 0; i < N; i++)        bestPath[i] = currentPath[i];  
  249.         }  
  250.     }  
  251.     else  
  252.         for(int i = 0; i < N; i ++)  
  253.          {  if(Valid(r,i))   
  254.              {    Node *q = new Node(r->level+1,i,r);  
  255.                 w += g.GetWeight(q->currentIndex,i);  
  256.                 if(w < bestV)       BackTrackExplicit(q);  
  257.                 w -= g.GetWeight(q->currentIndex,i);      
  258.             }  
  259.         }  
  260. }  
  261.   
  262.   
  263. void TspBase::Print() //  
  264.  {       fout<<"the shortest path is  ";  
  265.        for(unsigned i = 0; i < N; i++)  
  266.              fout<<bestPath[i] + 1<<"--";  
  267.        fout<<"1"<<endl;  
  268.        fout<<"minimum distance is  "<<bestV<<endl;         
  269. }  
  270.   
  271. void TspBase::TspBB()       // 分支限界法  
  272.  {        fout<<"TspBB(FIFOBB)  ........"<<endl;  
  273. cv = 0;        bestV = 100000;  
  274.         for(unsigned i = 0; i < N; i++)    currentPath[i] = i;  
  275.         root=new Node(0,-1,NULL);  
  276.         FIFOBB();  
  277.         Print();  
  278. }  
  279. void TspBase::FIFOBB()  
  280.  { queue<Node*> q;   Node *r;  
  281.   q.push(root);  
  282.   int w=0;  //初值  
  283.   while(!q.empty())  
  284.    {      r = q.front();      q.pop();  
  285.       if(r->level == N)  
  286.        { StoreX(r);  
  287.         cv = SumV();  
  288.         if(cv  < bestV)      
  289.          {   bestV = cv  ;  
  290.             for(int i = 0; i < N; i++)     bestPath[i] = currentPath[i];  
  291.         }  
  292.       }  
  293.       else  
  294.         for(int i = 0; i < N; i ++)  
  295.          {    if(Valid(r,i))   
  296.              {   Node *s = new Node(r->level+1,i,r);  
  297.                 w += g.GetWeight(s->currentIndex,i);  
  298.                 if(w < bestV)       q.push(s);  
  299.                 w -=  g.GetWeight(s->currentIndex,i);  
  300.             }  
  301.         }  
  302.   }  
  303. }  
  304. int TspBase::SumV()           //用于FIFOBB  
  305.  {    int s = 0;  
  306.     for(int i = 0; i < N; i++)  
  307.         s += g.GetWeight(currentPath[i],currentPath[(i + 1)%N]);  
  308.     return s;  
  309. }  
  310. void TspBase::TspGreedy()  //TSP贪心算法  
  311.  {     fout<<"TspGreedy ........"<<endl;  
  312. bestV = 0;       
  313.     vector<int> NEAR(N); //   
  314.     NEAR[0] = -1;  
  315.     for (int i = 1; i < N; i++)  
  316.        NEAR[i] = 0;  
  317.     bestPath[0] = 1;  
  318.     int t;  
  319.     for (int s = 1; s < N; s++)  
  320.      {  
  321.       int j = 1;  
  322.       while (j < N && NEAR[j] < 0) /   
  323.           j++;  
  324.       int K = j;  
  325.       for (int k = j + 1; k < N; k++)  
  326.          if (NEAR[k] >= 0 &&  g.GetWeight(k,NEAR[k]) < g.GetWeight(j,NEAR[j]))  
  327.                j = k;  
  328.       bestPath[s] = j + 1;  
  329.       bestV +=g.GetWeight(j,NEAR[j]);  
  330.       NEAR[j] = -1;  
  331.       for (k = K; k < N; k++) //调整NEAR值  
  332.          if (NEAR[k] >= 0)  
  333.              NEAR[k] = j;  
  334.       t = j;  
  335.     }  
  336.     bestV += g.GetWeight(t,0);  
  337.     fout<<"the shortest path is  ";  
  338.     for(unsigned w = 0; w < N; w++)  
  339.        fout<<bestPath[w] <<"--";  
  340.     fout<<"1"<<endl;  
  341.     fout<<"minimum distance is  "<<bestV<<endl;     
  342. }  
  343.   
  344. int main(int argc, char* argv[])  
  345.  {   int m,n;  
  346.     ifstream fin("data.txt");  
  347.     if(fin.bad()) return 1;  
  348.     fin >> m >> n;  
  349.     N = n;  
  350.     for(int i=0;i<N;i++)  g.InsertV(i);  
  351.     fin >> g;  
  352.     TspBase it;  
  353.     it.TspEnumImplicit();    it.DataClear(false);  
  354.   
  355.     it.TspBackTrackImplicit();    it.DataClear(false);  
  356.   
  357.     it.TspEnumExplicit();    it.DataClear(true);  
  358.   
  359.     it.TspBackTrackExplicit();    it.DataClear(true);  
  360.   
  361.     it.TspBB();    it.DataClear(true);  
  362.   
  363.     it.TspGreedy();    it.DataClear(false);  
  364.     return 0;  
  365. }  

 

 

执行结果:
the shortest path is  1--3--2--5--4--1
minimum distance is  20

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/351999.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

将字符串中的指定字符全局替换

// 将 str 中的 a 替换为 Avar str abcabcabc;var result str.replace(a, A);console.log(result: result); // 输出 result:Abcabcabc // 将str 中所有的 a 替换为 Avar str abcabcabc;var result str.replace(/a/g, A);console.log(result: result); // 输出 result:…

Lintcode--5(37)--反转一个三位数

1、题目反转一个只有3位数的整数。123 反转之后是 321。900 反转之后是 9。 2、我的解答 class Solution { public:/*** param number: A 3-digit number.* return: Reversed number.*/int reverseInteger(int number) {int num[3] {0};int result;num[1] number/100;num[2] …

java未检查异常_Java中已检查和未检查的异常

java未检查异常Java有两种类型的异常-已检查和未检查。 简而言之&#xff0c;选中的是指开发人员可以从异常中合理恢复的情况&#xff0c;而未选中的异常是无法处理的编程错误。 本文介绍了何时使用哪种。 但这不是那么简单–受检查的异常使代码变得“丑陋”。 它们迫使开发人员…

python清空列表clear_如何在Python中清空列表?

似乎很“肮脏”以这种方式清空列表&#xff1a;while len(alist) > 0 : alist.pop()是否存在明确的方法&#xff1f;#1楼list []将list重置为空列表。请注意&#xff0c;通常您不应list_保留的函数名称&#xff0c;例如list &#xff0c;它是列表对象的构造函数-例如&#…

linux shell 自定义函数(定义、返回值、变量作用域)介绍

linux shell 可以用户定义函数&#xff0c;然后在shell脚本中可以随便调用。下面说说它的定义方法&#xff0c;以及调用需要注意那些事项。 一、定义shell函数(define function) 语法&#xff1a; [ function ] funname [()] { action; [return int;] } 说明&#xff1a; …

Lintcode--6(767)--翻转数组

1、题目描述原地反转给定的数组&#xff0c;原地意味着你不能使用额外的空间。 2、AC程序 &#xff08;1&#xff09;利用C自带的函数 class Solution { public:void reverseArray(vector<int> &nums) {reverse(nums.begin(),nums.end());} }; &#xff08;2&#xf…

CPU时间分片、多线程、并发和并行

1、CPU时间分片、多线程&#xff1f; 如果线程数不多于CPU核心数&#xff0c;会把各个线程都分配一个核心&#xff0c;不需分片&#xff0c;而当线程数多于CPU核心数时才会分片。 2、并发和并行的区别 并发&#xff1a;当有多个线程在操作时,如果系统只有一个CPU,把CPU运行时间…

如何在Java中实现线程池

线程是独立程序的执行路径。 在java中&#xff0c;每个线程都扩展java.lang.Thread类或实现java.lang.Runnable。 多线程是指在一个任务中同时执行两个或多个线程。在多线程中&#xff0c;每个任务可以具有多个线程&#xff0c;并且这些线程可以异步或同步地并行运行。 您可以…

html选择按键点击后锁死输入框_js实现的键盘开启大写锁定提示和密码显示与隐藏的效果...

不知道大家注意到没有&#xff0c;很多人性话的网站再输入密码的时候&#xff0c;如果开启大写锁定下过(切换键A左边的Cap Lock按键)&#xff0c;那么就会给出一个提示&#xff0c;因为很多时候密码验证是区分大小写的&#xff0c;如果不小心开启或者关闭大小写就有可能导致输入…

vim ctags使用方法

windows下很多人都使用source insight 编写和查看代码。linux下可以使用VIM&#xff0c;刚开始会觉得VIM像windows下的记事本&#xff0c;而如果使用得当&#xff0c;它并不比source insight 逊色。在这里&#xff0c;我会尽我所能细致地讲清楚如何把vim变成source insight, 然…

MATLAB读取txt文件的数据

常用的主要有以下几种方法&#xff1a; 1、loadData load("filename.txt");该函数只能加载仅含有数字的文本文件&#xff0c;如果文档中夹杂着字母或者文字&#xff0c;就会报错。 2、importdataData importdata("filename.txt");既可以读取数据又可以读…

谷歌guava_Google Guava v07范例

谷歌guava我们在TouK举办了一个名为“每周技术研讨会”的活动&#xff0c;即每个星期五的16:00&#xff0c;每个愿意参加的人都有一个演讲。 我们展示了我们在家学习和学习的东西&#xff0c;但是我们还设有一个公告板&#xff0c;上面有人们想听的话题。 上周MaciejPrchniak谈…

arduinoesp8266定时器_ESP8266深度睡眠与Arduino IDE(NodeMCU)

本指南展示了如何使用Arduino IDE与ESP8266(NodeMCU)一起使用深度睡眠。我们将使用定时器唤醒来唤醒深度睡眠&#xff0c;并使用复位(RST)引脚来唤醒外部唤醒。引入深度睡眠模式如果您使用电池供电的ESP8266板制作了一个项目&#xff0c;或者只是将ESP8266 NodeMCU板连接到了移…

MATLAB对图片格式批量转换

从网上下载一些数据集&#xff0c;发现是PPM或者PGM格式的&#xff0c;一般照片查看器打不开。可以用MATLAB对其进行批量转换格式。当然&#xff0c;任何两种格式之间相互转换都可以用这个程序&#xff1a;% 本示例程序将 pgm 图片转换为 jpg 图片 % 如果仅对一张 pgm 图片作…

gunicorn部署Flask服务

作为一个Python选手&#xff0c;工作中需要的一些服务接口一般会用Flask来开发。 Flask非常容易上手&#xff0c;它自带的app.run(host"0.0.0.0", port7001)用来调试非常方便&#xff0c;但是用于生产环境无论是处理高并发还是鲁棒性都有所欠缺&#xff0c;一般会配合…

linux shell 中判断字符串为空的正确方法

help命令可以查看帮助 help test 正确做法&#xff1a; #!/bin/sh STRING if [ -z "$STRING" ]; then echo "STRING is empty" fi if [ -n "$STRING" ]; then echo "STRING is not empty" fi rootjames-desktop:~#…

打开wmware没反应_没呼吸没脉搏,溺水女孩危在旦夕!预产期只差9天的她挺着大肚子出手相助...

8月9日晚上8点半南海桂城中海锦城小区游泳池一位小女孩溺水了&#xff01;脸色青紫、嘴唇发绀没有呼吸也没有脉搏情况非常不妙&#xff01;↓↓↓救生员立马给女孩做心肺复苏。站在泳池边陪女儿才游不到200米的南海医院妇科医生胡碧洪&#xff0c;听见泳池边的骚动&#xff0c;…

使用JAXB的简介

我正在将一些依赖于Apache XMLBeans的模块迁移到JAXB。 这是令人兴奋且充满挑战的几天。 我想记下我遇到的一些重要事情&#xff0c;以供将来可能会发现有用的任何人使用。 首先&#xff0c;让我们来看一下设置用于JAXB代码生成的maven插件。 在撰写本文时&#xff0c;我遇到了…

关于opencv读取摄像头的未解之谜

前段时间做项目需要用opencv读usb摄像头的视频数据&#xff0c;遇到很多无解的问题&#xff0c;虽然后来没有用到&#xff0c;但是还是记录下来&#xff0c;也许以后就知道答案了呢。 1、无论摄像头的实际分辨率是多少&#xff0c;opencv读进来的视频分辨率都是640*480大小的&a…

[BZOJ2834]回家的路

Description Input Output Sample Input 2 1 1 2 1 1 2 2Sample Output 5思路还是很简单的&#xff0c;然而最短路打错各种对拍各种调了一早上代码&#xff1a;1 #include<iostream>2 #include<cstdio>3 #include<cstring>4 #include<vector>5 #includ…