哈密顿回路

哈密顿回路

中文名 哈密顿回路
说明 是一个无向图
目录导航

由来

哈密顿回路哈密顿回路天文学家哈密顿(William Rowan Hamilton) 提出,在一个有多个城市的地图网络中,寻找一条从给定的起点到给定的终点沿 途恰好经过所有其他城市一次的路径。

这个问题和著名的七桥问题的不同之处在于,过桥只需要确定起点,而不用确定终点。哈密顿问题寻找一条从给定的起点到给定的终点沿 途恰好经过所有其他城市一次的路径。

算法

哈密顿路径问题在上世纪七十年代初,终于被证明是“NP完全”的。据说具有这样性质的问题,难于找到一个有效的算法。实际上对于某些顶点数不到100的网络,利用现有最好的算法和计算机也需要比较荒唐的时间(比如几百年)才能确定其是否存在一条这样的路径。

从图中的任意一点出发,路途中经过图中每一个结点当且仅当一次,则成为哈密顿回路。

要满足两个条件:

⒈封闭的环

⒉是一个连通图,且图中任意两点可达

经过图(有向图或无向图)中所有顶点一次且仅一次的通路称为哈密顿通路。

经过图中所有顶点一次且仅一次的回路称为哈密顿回路。

具有哈密顿回路的图称为哈密顿图,具有哈密顿通路但不具有哈密顿回路的图称为半哈密顿图。

平凡图是哈密顿图。

⒊若以1到2、2到3、3到4、4到5、5到1,为计数规律,则各点均出现两次;这种判断方法在计算机编程运算中显得尤为重要,其会精简很多运算过程。

⒋新出炉,有待检测的代码如下:

注:这段代码采用分支定界法作为编写程序的依据,因此代码依旧局限在算法上;而且代码的使用对所要计算的数据是有要求的,如下:

⒈只要数据在开始计算出的n个最小值中,其重复次数超过2次的点的种类只能为一种,例如:代码段中的数据五个最小值中其重复次数超过2次的点只有v5。

⒉数据矩阵格式要求:只允许为上三角矩阵,不支持全矩阵以及下三角矩阵的运算。

⒊代码扩展方法请使用者独立思考,不唯一。

⒋运算数据扩展方法,请使用者独立思考,不唯一。

⒌此代码为本人毕设的附加产品,不会对使用此代码者,因理解不当或使用不当而造成的任何不良后果,付出任何责任。

⒍代码仅供交流。

代码示例

C代码

#include#include#include#include#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
#define MAX_VER_NUM 11//顶点的最大数
#define MAX_ARC_NUM 22//边的最大数
typedef char VertexType;
typedef int Status;
typedef struct EdgeInfo {
    VertexType v1;
    VertexType v2;
    int weight;
}EdgeInfo;
typedef struct ArcBox//边所包含的信息 {
    int iver;
    struct ArcBox *ilink;
    int jver;
    struct ArcBox *jlink;
    int weight;//权值
    int mark;
    char *info;
}ArcBox;
typedef struct VerBox//顶点所包含的信息 {
    VertexType data;//顶点值
    ArcBox *firstedge;//指向邻接点(边所包含的信息)
}VerBox;
typedef struct Graph {
    int vernum;//顶点总个数
    int arcnum;//边的总个数
    VerBox vertexs[MAX_VER_NUM];//顶点信息
}Graph;
typedef struct StackData//栈中可存放的数据 {
    VertexType data;
    int lenght;
    struct StackData *pnext;
}StackData;
typedef struct Stack//栈用于存放已访问过的顶点 {
    struct StackData *ptop;
    struct StackData *pbottom;    
}STNODE;
typedef struct Stack_Arc//存方已访问过的边及顶点 {
    ArcBox *p[MAX_ARC_NUM];
    int v_num[MAX_ARC_NUM];
}SANode;
int Visited[MAX_VER_NUM];//标记顶点是否被访问过
EdgeInfo Data[MAX_ARC_NUM]={{'A','B',324},{'A','J',419},{'A','K',328},{'A','D',241},{'A','C',556},{'A','F',703},{'A','G',521},{'B','G',391},{'B','H',230},{'B','I',356},{'B','J',220},{'C','F',642},{'C','E',337},{'D','F',829},{'D','K',334},{'E','F',581},{'E','G',1254},{'F','G',887},{'G','H',242},{'H','I',249},{'I','J',713},{'J','K',398}};//边及权值
int Count=0;//记可走边的总数
STNODE Stack;//存放已访问过
SANode Store_Arc_Ver;//存放弧的信息及顶点信息
int LAV=-1,ALL=0;
int Short_Len=1000000,Short_Load=0;//存放最断最路经
void CreateGraph(Graph **G);//创建图
int LocateVer(Graph G,VertexType v);//查找顶点v在图中的位置
void ShowAdjInfo(Graph *G);//查看邻接点信息
int FirstAdjVer(Graph *G,int v,ArcBox **u);//第一邻接点
int NextAdjVer(Graph *G,int v,int w,ArcBox **u);//下一邻接点
void NAV(ArcBox *p,int *n,int v,int w,ArcBox **u);//递归查找下一邻接点
void InitArcBox_mark(ArcBox *p);//初始化mark的值
void DFSTraverse(Graph *G);//深度优先遍历图
void DFST(Graph *G,int v);//剃归深度优先遍历
void InitStack(void);//初始化栈
void Push(VertexType c);//数据进栈
void Pop(void);//出栈
Status IsAdj(int *len,VertexType v);//判断栈顶的点是否与A为邻接点
int main() {
    Graph *G=NULL;
    CreateGraph(&G);
    printf("顶点的邻接表:\n");
    ShowAdjInfo(G);printf("\n\n");
    printf("可走路径结果:\n");
    DFSTraverse(G);printf("\n");
    printf("可走路径总数:%d条;最短路径为:路径%d,长度为:%d\n\n",ALL,Short_Load,Short_Len);
    return 0;
}
void CreateGraph(Graph **G)//创建图 {
    int i,j,k,w;
    char v1,v2;
    ArcBox *pnew;
    (*G)=(Graph *)malloc(1*sizeof(Graph));
    if((*G)==NULL)
    {
        printf("动态内存分配失败,程序终止!\n");
        exit(-1);
    }
    (*G)->arcnum=MAX_ARC_NUM;
    (*G)->vernum=MAX_VER_NUM;
    for(i=0;i<(*G)->vernum;i++)
    {
        (*G)->vertexs[i].data='A'+i;
        (*G)->vertexs[i].firstedge=NULL;
    }
    for(k=0;k<(*G)->arcnum;k++)
    {
        v1=Data[k].v1;
        v2=Data[k].v2;
        w=Data[k].weight;
        i=LocateVer((**G),v1);
        j=LocateVer((**G),v2);
        if(i>=0&&j>=0)
        {
            pnew=(ArcBox *)malloc(1*sizeof(ArcBox));
            if(pnew==NULL)
            {
                printf("动态内存分配失败,程序终止!\n");
                exit(-1);
            }            
            pnew->iver=i;
            pnew->jver=j;
            pnew->weight=w;
            pnew->mark=FALSE;
            pnew->ilink=(*G)->vertexs[i].firstedge;
            pnew->jlink=(*G)->vertexs[j].firstedge;
            (*G)->vertexs[i].firstedge=pnew;
            (*G)->vertexs[j].firstedge=pnew;
        }
        else
        {
            printf("注意:*****顶点%c不存在!*****\n",i<0?v1:v2);
        }
    }
    return;
}
int LocateVer(Graph G,VertexType v)//查找顶点v在图中的位置 {
    int i,result=-1;
    for(i=0;ivernum;v++)
    {
        printf("[%d|%c]",v,G->vertexs[v].data);
        for(w=FirstAdjVer(G,v,&u);w>=0;w=NextAdjVer(G,v,w,&u))
        {
            printf("->[%d|%c|%d]",w,G->vertexs[w].data,u->weight);
        }
        InitArcBox_mark(G->vertexs[v].firstedge);
        printf("\n");
    }
}
int FirstAdjVer(Graph *G,int v,ArcBox **u)//第一邻接点 {
    int w=-1;
    ArcBox *p;
    p=G->vertexs[v].firstedge;
    (*u)=p;
    if(v==p->iver)
    {
        w=p->jver;
        p->mark=TRUE;
    }
    else if(v==p->jver)
    {
        w=p->iver;
        p->mark=TRUE;
    }
    return w;
}
int NextAdjVer(Graph *G,int v,int w,ArcBox **u)//下一邻接点 {
    int n=-1;
    ArcBox *p;
    (*u)=NULL;
    p=G->vertexs[v].firstedge;
    NAV(p,&n,v,w,&(*u));
    return n;
 
}
void NAV(ArcBox *p,int *n,int v,int w,ArcBox **u)//递归查找下一邻接点 {
    if(p->mark==FALSE && (p->iver==v ||p->jver==v))
    {
        (*u)=p;
        if(p->iver==v)
        {
            *n=p->jver;p->mark=TRUE;
        }
        else if(p->jver==v)
        {
            *n=p->iver;p->mark=TRUE;
        }
        else printf("下一邻接点数据出错,请检查!\n");
    }
    else
    {
        if(p->ilink!=NULL && *n==-1)
        {
            NAV(p->ilink,n,v,w,&(*u));
        }
        if(p->jlink!=NULL && *n==-1)
        {
            NAV(p->jlink,n,v,w,&(*u));
        }
    }
    return;
}
void InitArcBox_mark(ArcBox *p)//初始化mark的值 {
    p->mark=FALSE;
    if(p->ilink!=NULL)
    {
        InitArcBox_mark(p->ilink);
    }
    if(p->jlink!=NULL)
    {
        InitArcBox_mark(p->jlink);
    }
    return;
}
void DFSTraverse(Graph *G)//深度优先遍历图 {
    int v;
    for(v=0;vvernum;v++)
    {
        Visited[v]=FALSE;
        InitArcBox_mark(G->vertexs[v].firstedge);
    }
    InitStack();
    DFST(G,0);        
    return;
}
void DFST(Graph *G,int v)//剃归深度优先遍历 {
    int w=-1,flag=1,i=0,enter=1,len=0;
    ArcBox *u;//邻接点
    StackData *p;
    Visited[v]=TRUE;
    Count++;
    Push(G->vertexs[v].data);
    if(Count==11&&IsAdj(&len,Stack.ptop->data)==1) 
    {        
        ALL++;
        printf("路径%-2d:",ALL);
        printf("A");
        p=Stack.ptop;
        len=len+p->lenght;
        if(Short_Len>len) Short_Load=ALL,Short_Len=len;        
        while(p!=Stack.pbottom)
        {
            printf("->%c",p->data);
            p=p->pnext;
        }
        printf(" 总长度为:%d",len);
        printf("\n");
    }
    for(w=FirstAdjVer(G,v,&u);w>=0;w=NextAdjVer(G,v,w,&u))
    {
        enter=1;
        for(i=0;i<=LAV;i++)
        {
            if(Store_Arc_Ver.p[i]==u)
            {
                enter=0;
                break;
            }
        }
        if(enter==1)
        {
            Store_Arc_Ver.p[++LAV]=u;
            Store_Arc_Ver.v_num[LAV]=v;
        }
        if(Visited[w]==FALSE)
        {    
            DFST(G,w);
            Visited[w]=FALSE;
            Count--;
            Pop();
        }
    }
    for(LAV;Store_Arc_Ver.v_num[LAV]==v&&LAV>=0;)//还原当前顶点边的状态并出栈
    {
        Store_Arc_Ver.p[LAV]->mark=FALSE;
        Store_Arc_Ver.p[LAV]=NULL;
        LAV--;
    }
}
void InitStack(void)//初始化栈 {
    Stack.pbottom=Stack.ptop=(StackData *)malloc(1*sizeof(StackData));
    Stack.pbottom->pnext=NULL;
    return;
}
void Push(VertexType c)//数据进栈 {
    StackData *pnew;
    char v1,v2;
    int i;
    pnew=(StackData *)malloc(1*sizeof(StackData));
    pnew->data=c;
    if(c=='A')
    {
        pnew->lenght=0;
    }
    else
    {
        v1=c;
        v2=Stack.ptop->data;
        for(i=0;ilenght=Stack.ptop->lenght+Data[i].weight;
            }
        }
    }
    pnew->pnext=Stack.ptop;
    Stack.ptop=pnew;
    return;
}
void Pop(void)
{
    StackData *p;
    p=Stack.ptop;
    Stack.ptop=p->pnext;
    free(p);
}
Status IsAdj(int *len,VertexType v)//判断是栈顶的点是否与A为邻接点
{
    int i;
    for(i=0;i

C++代码

#include#include#include#include#include#include#include#include#include#include#include#include#include#define max(a,b) (a>b?a:b)
using namespace std;
typedef long long(LL);
typedef unsigned long long(ULL);
const double eps(1e-8);
 
char B[1<<15],*S=B,*T=B,ch;
#define getc() (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?0:*S++)
int aa,bb; int F() {
      while(ch=getc(),(ch<'0'||ch>'9')&&ch!='-'); ch=='-'?aa=bb=0:(aa=ch-'0',bb=1);
      while(ch=getc(),ch>='0'&&ch<='9')aa=aa*10+ch-'0'; return bb?aa:-aa;
}
#define N 100010
int n,swp,cnt,z[N]; long long ans;
#define swap(a,b) (swp=a,a=b,b=swp)
#define abs(x) (x>0?x:-(x))
#define max(a,b) (a>b?a:b)
#define cmax(x) (ans<(const="" p&a,const="" p&b)="" {return="" a.nx<<2];="" e="" to,v,nxt;}="" e[n<<1];="" gf(int="" x)="" ufs[x]="=x?x:ufs[x]=gf(ufs[x]);}" void="" adde(int="" x,int="" y,int="" v)="" e[++et]="(E)" {y,v,la[x]},la[x]="et;" {x,v,la[y]},la[y]="et;" public:="" graph()="" {et="1;}" add(int="" {d[++tot]="(D)" {x,y,v};}="" make()="" std::sort(d+1,d+1+tot);="" for(int="" i="1;" i<="n;" i++)ufs[i]="i;" cnt="n;" i++)="" if((x="gf(d[i].x))!=(y=gf(d[i].y)))" adde(d[i].x,d[i].y,d[i].v);="" g;="" x,n;}="" d[n];="" d&a,const="" d&b)="" a.x<="cnt;" f="0;">0; t-=t&-t)
            if(z[t]&&(f==0||p[z[t]].x+p[z[t]].y>p[f].x+p[f].y))f=z[t];
      return f;
}
void work() {
      for(int i=1; i<=n; i++)p[i].nx=p[i].x-p[i].y,p[i].ny=p[i].y;
      std::sort(p+1,p+1+n);
      for(int i=1; i<=n; i++)d[i]=(D) {p[i].ny,i};
      std::sort(d+1,d+1+n); d[n+1].x=d[n].x; cnt=1;
      for(int i=1; i<=n; i++)
      {
            p[d[i].n].ny=cnt;
            if(d[i].x!=d[i+1].x)cnt++;
      }
      memset(z,0,sizeof(z));
      for(int i=1,j; i<=n; ins(i++))
            if(j=query(i))G.add(p[i].id,p[j].id,dis(i,j));
}
int main() {
      n=F();
      for(int i=1; i<=n; i++)p[i]=(P) {F(),F(),i}; work();
      for(int i=1; i<=n; i++)swap(p[i].x,p[i].y); work();
      for(int i=1; i<=n; i++)p[i].y=-p[i].y; work();
      for(int i=1; i<=n; i++)swap(p[i].x,p[i].y); work(); G.make();
      printf("%lld\n",ans);
}
/* * this code is made by crazyacking * Verdict: Accepted * Submission Date: 2015-09-11-15.31 * Time: 0MS * Memory: 137KB */

相关百科
返回顶部
产品求购 求购