HDOJ  4337   King Arthur's Knigh…

题目:http://acm.hdu.edu.cn/showproblem.php?pid=4337

题目感觉用深搜,

#include <stdio.h>
#include <string.h>
#define MAX 200
int n,m,step;
int map[MAX][MAX];
int visit[MAX];
bool pass[MAX],flag;
void dfs(int x,int step)
{
    int i,j;
    pass[x]=true;
    if(step==n&&map[x][1]==1)
    {
        flag=true;
        return ;
    }
    if(flag||step==n)
        return ;
    for(i=1;i<=n&&!flag;i++)
    {
        if(map[x][i]==1&&!flag&&!pass[i])
        {
            visit[step+1]=i;
            dfs(i,step+1);
            if(!flag)
                pass[i]=false;
        }
    }
}
int main()
{
    int a,b,i,j;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        memset(pass,false,sizeof(pass));
        memset(map,0,sizeof(map));
        for(i=1;i<=m;i++)
        {
            scanf("%d%d",&a,&b);
            map[a][b]=map[b][a]=1;
        }
        step=1;
        flag=false;
        visit[step]=1;
        dfs(1,1);
        if(flag)
        {
            for(i=n;i>1;i--)
                printf("%d ",visit[i]);
            printf("%d\n",visit[1]);
        }
        else
            printf("no solution\n");
    }
    return 0;
}
标程,题解:自己感觉不是很理解,,,但在这里写一下

构造一个特殊图的Hamilton回路。首先随机得到一个环序列a1, a2, ..., an, 如果a(i)->a(i+1)在图中没有边,因为每个点至少和一半的点有边相连,于是一定可以找到另一个点j,满足a(i)-a(j)有边,a(i+1)-a(j+1)有边。然后反转环中a(i+1)a(j)这一段序列,即可令环上存在的边数增加12(取决于原来的环上a(j)->a(j+1)是否有边)。继续此过程直到环上所有的边都存在。

 #include <cstdio>
#include <algorithm>
#include <cassert>
#include <cstring>

const int MAXN = 160;
int mp[MAXN][MAXN];
int ans[MAXN], n, deg[MAXN];

void rev(int L, int R) {
    while (L != R) {
        std::swap(ans[L], ans[R]);
        if (++L == n) L = 0;
        if (L == R) break;
        if (--R == -1) R = n - 1;
    }
}

int solve() {
    int i, j;
    for (i = 0 ; i < n ; i++) {
        if (mp[ans[i]][ans[(i+1)%n]] == 0) break;
    }
    if (i == n) return 0; // done

    for (j = 0 ; j < n ; j++) {
        if (j == i || j == (i+1)%n || (j+1)%n == i) continue;
        if (mp[ans[i]][ans[j]] && mp[ans[(i+1)%n]][ans[(j+1)%n]]) {
            // printf("rev(%d,%d)\n",(i+1)%n,j);
            rev((i+1)%n, j);
            return 1;
        }

    }
    assert(false);
    return 1;
}

int main() {
    freopen("data.in","r",stdin);
    freopen("data.out","w",stdout);
    int m, ca = 0;
    while (scanf("%d%d",&n,&m) != EOF) {
        memset(mp, 0, sizeof(mp));
        memset(deg, 0, sizeof(deg));
        while (m--) {
            int t1, t2;
            scanf("%d%d",&t1,&t2);
            --t1; --t2;
            assert(t1 != t2 && mp[t1][t2] == 0);
            mp[t1][t2] = mp[t2][t1] = 1;
            ++deg[t1];
            ++deg[t2];
        }
        for (int i = 0 ; i < n ; i++)
            assert(deg[i] >= (n+1) / 2);
        for (int i = 0 ; i < n ; i++)
            ans[i] = i;
        int cnt = 0;
        while (solve());
        for (int i = 0 ; i < n ; i++)
            printf("%d ",ans[i]+1);
        printf("\n");
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值