哈密顿图

哈密顿图,存在哈密顿回路的图。

哈密顿路径。


1.当度数最小的2个点的度数之和大于等于n时,存在哈密顿路径


poj2438

给定2个人之间有敌对关系,不能坐在一起。

给定有敌对关系的点,求是否存在哈密顿路径?

#include <iostream>

#include <cstdio>

#include <cstring>

using namespace std;

const int maxn = 400 + 5;


int mp[maxn][maxn];

int ans[maxn];

int vis[maxn];

int s,t;

int n,m;

int cnt = 0;


void init()

{

    memset(ans, 0, sizeof(ans));

    memset(vis, 0, sizeof(vis));

    cnt = 0;

    memset(mp, -1, sizeof(mp));

    for(int i = 1;i <= n;i ++) mp[i][i] = 0;

}

void rev(int s,int t)

{

    while (s < t) {

        swap(ans[s], ans[t]);

        s ++,t --;

    }

}

void expand()

{

    while (1) {

        bool fg = 0;

        for (int i = 1; i <= n; i ++) {

            if(!vis[i] && mp[t][i]){

                ans[cnt ++] = i;

                t = i;

                vis[i] = 1;

                fg = 1;

                break;

            }

        }

        if(!fg) break;

    }

}


void hamilton()

{

    s = 1;

    for (int i = 1; i <= n; i ++) {//取任意和s相邻的点当做t

        if(mp[1][i]){t = i;break;}

    }

    vis[s] = vis[t] = 1;

    ans[0] = s,ans[1] = t;

    cnt = 2;

    while (1) {

        expand();

        rev(0, cnt - 1);

        swap(s, t);

        expand();//从s扩展,翻转ans,交换s和t,再从s扩展

        

        int mid = 0;

        if(!mp[s][t]){

            for (int i = 1; i < cnt - 2; i ++) {

                if(mp[ans[i]][t] && mp[ans[i + 1]][s]){

                    mid = i + 1;

                    break;

                }

            }

            rev(mid, cnt - 1);

            t = ans[cnt - 1];

        }

        

        if(cnt == n) break;

        //????

        for (int i = 1; i <= n; i ++) {

            if(vis[i]) continue;

            int j;

            for (j = 1; j < cnt - 1; j ++) {

                if(mp[ans[j]][i]){mid = j;break;}

            }

            if(mp[ans[mid]][i]){t = i;mid = j;break;}

        }

        //???

        s = ans[mid - 1];

        rev(0, mid - 1);

        rev(mid, cnt - 1);

        ans[cnt ++] = t;

        vis[t] = 1;

    }

}


int main()

{

    while (scanf("%d%d",&n,&m) != EOF) {

        if(n == 0 && m == 0) break;

        n *= 2;

        int a,b;

        init();

        for (int i = 0; i < m; i ++) {

            scanf("%d%d",&a,&b);

            mp[a][b] = mp[b][a] = 0;

        }

        hamilton();

        for (int i = 0; i < cnt; i ++) {

            printf("%d%c",ans[i],i == cnt - 1 ? '\n' : ' ');

        }

    }

    return 0;

}

2.竞赛图,为无向完全图中的每条边赋与方向。

n >= 2的时候一定存在哈密顿路径。


hdu3414 求是否存在哈密顿回路

#include <iostream>

#include <cstdio>

#include <cstring>

using namespace std;

const int maxn = 1000 + 5;

bool mp[maxn][maxn];

int n;

int nex[maxn];


bool expand(int s)

{

    memset(nex, -1, sizeof(nex));

    int head = s,tail = s;

    for (int i = 1; i <= n; i ++) {

        if(i == s) continue;

        if(mp[i][head]){//i到head有路径就直接添加

            nex[i]= head;

            head = i;

        }

        else{//i到head没有路径,那么head到i一定有路径(竞赛图的性质)

            int x = head,y = nex[head];

            while (y != -1 && mp[y][i]) {//如果y到i有路径就一直向后递归//递归的过程,保证x到i有路径,且在y到i无路径时结束(即i到y有路径)

                x = y;

                y = nex[y];

            }

            nex[x] = i; //  将i添加到答案中

            nex[i] = y;

            if(y == -1) tail = i;//如果x是最后一个,那就将i添至尾部tail

        }

    }

    if(mp[tail][head]){//判断是否是回路

        nex[tail] = head;

        return true;

    }

    return false;

}

bool solve()

{

    for (int i = 1; i <= n; i ++) {

        if(expand(i)) return true;

    }

    return false;

}

int main()

{

    while (scanf("%d",&n) != EOF) {

        if(n == 0 ) break;

        for (int i = 1; i <= n; i ++) {

            for (int j = 1; j <= n; j ++) {

                scanf("%d",&mp[i][j]);

            }

        }

        if(n == 1) printf("1\n");

        else if(n == 2 || !solve()) printf("-1\n");

        else {

            int cnt = 0;

            for (int p = 1; cnt < n; p = nex[p]) {

                cnt ++;

                printf("%d%c",p,cnt == n? '\n' : ' ');

            }

        }

        

    }

    return 0;

}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值