[hackerrank]Walking the Longest Path (Approximation Problem)

题目大意

求一条尽可能长的哈密顿路径,并输出。
保证存在长度为n的哈密顿路径。
你找的哈密顿路径长度至少为n*0.95且合法即算对。

随机算法

这个不可做,因此考虑随机算法。
我们随机它个800次!
每次随机一个中间点w,然后从w拓展出两条不相交的路径作为本次搜出的哈密顿路径。
每个点i用一个d[i]表示i有多少出边连向的点不在目前找到的哈密顿路径中,接下来d用度数称呼。
每次对于当前点k,如果k存在一个相连的不在哈密顿路径中的度数为1的点,那么我们就将其加入哈密顿路径中,然后更新当前点。
这是为什么呢?因为我们希望尽可能捅进那条可行长度为n的链。(纯口胡)
找不到度数为1的点,就随机一个相邻不在哈密顿路径中的点走过去。
做两次上述算法就得到一条哈密顿路径。
重复这个过程800次(或更多或更少,随你便),以最长的哈密顿路径作为答案。

#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=10000+10,maxm=100000+10;
int ans[maxn],d[maxn],now[maxn],a[maxn],b[maxn],c[maxn];
int h[maxn],go[maxm*2],nex[maxm*2];
bool bz[maxn];
int i,j,k,w,l,t,n,m,tot,ca;
int read(){
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9'){
        if (ch=='-') f=-1;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
int random(int x){
    int t=rand()%10000;
    t=t*10000+rand()%10000;
    return t%x;
}
void add(int x,int y){
    d[y]++;
    go[++tot]=y;
    nex[tot]=h[x];
    h[x]=tot;
}
int main(){
    n=read();m=read();
    fo(i,1,m){
        j=read();k=read();
        add(j,k);add(k,j);
    }
    ca=800;
    while (ca--){
        fo(i,1,n) now[i]=d[i],bz[i]=0;
        k=random(n)+1;
        w=k;
        a[a[0]=1]=k;
        bz[k]=1;
        while (1){
            c[0]=0;
            j=0;
            t=h[k];
            while (t){
                now[go[t]]--;
                if (now[go[t]]==1&&!bz[go[t]]) j=go[t];
                if (!bz[go[t]]) c[++c[0]]=go[t];
                t=nex[t];
            }
            if (!c[0]) break;
            if (!j) j=c[random(c[0])+1];
            bz[j]=1;
            a[++a[0]]=j;
            k=j;
        }
        k=w;
        b[b[0]=1]=k;
        while (1){
            c[0]=0;
            j=0;
            t=h[k];
            while (t){
                if (k!=w) now[go[t]]--;
                if (now[go[t]]==1&&!bz[go[t]]) j=go[t];
                if (!bz[go[t]]) c[++c[0]]=go[t];
                t=nex[t];
            }
            if (!c[0]) break;
            if (!j) j=c[random(c[0])+1];
            bz[j]=1;
            b[++b[0]]=j;
            k=j;
        }
        if (a[0]+b[0]-1>ans[0]){
            ans[0]=a[0]+b[0]-1;
            fd(i,a[0],1) ans[a[0]-i+1]=a[i];
            fo(i,2,b[0]) ans[a[0]+i-1]=b[i];
        }
    }
    printf("%d\n",ans[0]);
    fo(i,1,ans[0]) printf("%d ",ans[i]);
    printf("\n");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值