数据结构PTA 基础实验6-2.2 汉密尔顿回路

基础实验6-2.2 汉密尔顿回路

题目

著名的“汉密尔顿(Hamilton)回路问题”是要找一个能遍历图中所有顶点的简单回路(即每个顶点只访问 1 次)。本题就要求你判断任一给定的回路是否汉密尔顿回路。

输入格式:
首先第一行给出两个正整数:无向图中顶点数 N(2<N≤200)和边数 M。随后 M 行,每行给出一条边的两个端点,格式为“顶点1 顶点2”,其中顶点从 1 到N 编号。再下一行给出一个正整数 K,是待检验的回路的条数。随后 K 行,每行给出一条待检回路,格式为:
n V1​​ V​2 ⋯ Vn
其中 n 是回路中的顶点数,Vi是路径上的顶点编号。

输出格式:
对每条待检回路,如果是汉密尔顿回路,就在一行中输出"YES",否则输出"NO"。

输入样例:

6 10
6 2
3 4
1 5
2 5
3 1
4 1
1 6
6 3
1 2
4 5
6
7 5 1 4 3 6 2 5
6 5 1 4 3 6 2
9 6 2 1 6 3 4 5 2 6
4 1 2 5 1
7 6 1 3 4 5 2 6
7 6 1 2 5 4 3 1

输出样例:

YES
NO
NO
NO
YES
NO

解法

思路
根据Hamilton回路的特点,一个回路要是Hamilton回路需要具备以下特点:

  1. 它是个回路,即起始点和终止点需要相等。
  2. 它遍历了图上所有的点,且各点只访问一次。
  3. 它中间走过的路径是存在的。

根据以上特点,具体可以这样操作:

  1. 用一个邻接矩阵的结构来存储图的信息
  2. 对于需要判定的回路,首先判断其输入的点是否为Graph->Nv+1,如果不是,直接输出NO,如果是则读取。
  3. 用一个InputArr数组存储输入的点,用Visited数组来标记数组角标对应编号的顶点是否访问。在这一步读入的时候,可以直接去判断输入回路是否满足条件1,当然也可以放在下面的步骤判断。
  4. 每次都用InputArr数组相邻两个元素判断,看这两个元素是否有边相连,一旦没有,输出NO。有的话,把InputArr数组中后一个元素的Visited标记置为1.
  5. 完成后检查Visited的标记是否全为1,如果不全为1就说明不满足条件2,输出NO。

实现

#include<stdio.h>
#include<stdlib.h>

#define MAXN 200
#define INFINITY 100000

typedef int WeightType;
typedef int Vertex;

typedef struct GNode *PtrToGNode;
typedef PtrToGNode MGraph;
struct GNode
{
    int Nv;
    int Ne;
    WeightType G[MAXN][MAXN];
};

typedef struct ENode *PtrToENode;
typedef PtrToENode Edge;
struct ENode
{
    Vertex V1, V2;
    WeightType W;
};

MGraph CreateGraph(int VertexNum)
{
    MGraph Graph = (MGraph)malloc(sizeof(struct GNode));
    Graph->Nv = VertexNum;
    Graph->Ne = 0;

    Vertex i,j;
    for(i=0; i<Graph->Nv; i++)
        for(j=0; j<Graph->Nv; j++)
            Graph->G[i][j] = INFINITY;

    return Graph;
}

void InsertEdge(MGraph Graph, Edge E)
{
    Graph->G[E->V1][E->V2] = E->W;
    Graph->G[E->V2][E->V1] = E->W;
}

MGraph BuildGraph(int VertexNum, int EdgeNum)
{
    MGraph Graph = CreateGraph(VertexNum);
    Graph->Ne = EdgeNum;

    Edge E = (Edge)malloc(sizeof(struct ENode));
    int i;
    for(i=0; i<Graph->Ne; i++)
    {
        scanf("%d %d", &E->V1, &E->V2);
        E->V1--;
        E->V2--;
        E->W = 1;
        InsertEdge(Graph, E);
    }

    return Graph;
}

int IsEdge(MGraph Graph, Vertex V1, Vertex V2)
{
    if(Graph->G[V1][V2] == INFINITY)
        return 0;
    else
        return 1;
}

int main()
{

    int N, M, K, TN, i, j, tmp;
    Vertex InputArr[MAXN+1] = {0};
    int Visited[MAXN] = {0};

    scanf("%d %d", &N, &M);
    MGraph Graph = BuildGraph(N, M);

    scanf("%d", &K);
    for(i=0; i<K; i++)
    {
        scanf("%d", &TN);
        if(TN != Graph->Nv+1)
        {
            printf("NO\n");
            while(TN != 0)
            {
                scanf("%d", &tmp);
                TN--;
            }
        }
        else
        {
            //clear the Visited arr
            for(j=0; j<Graph->Nv; j++)
            {
                Visited[j] = 0;
            }

            //

            for(j=0; j<Graph->Nv+1; j++)
            {
                scanf("%d", &InputArr[j]);
                InputArr[j]--;
            }
            for(j=0; j<Graph->Nv; j++)
            {
                if(IsEdge(Graph, InputArr[j], InputArr[j+1]))
                    Visited[InputArr[j+1]] = 1;
                else
                {
                    printf("NO\n");
                    break;
                }
            }
            if(j == Graph->Nv)
            {
                for(j=0; j<Graph->Nv; j++)
                {
                    if(Visited[j] == 0)
                    {
                        printf("NO\n");
                        break;
                    }
                }
                if(j == Graph->Nv)
                    printf("YES\n");
            }
        }
    }


    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值