poj 1945 Power Hungry Cows 启发式搜索

这个题目用了启发式搜索来做,hash判重,优先队列储存节点。启发式函数就是大的数字x*2^k>n,即为k。
x为节点中较大值,y为节点中较小值
然后后面就是一些剪枝了,当x>2*n不能得出最优解。当y==0,不能得出最优解。当x==y,不能得出最优解。
还有一个比较关键的剪枝,gcd(x,y)不能整除n时,得不出结果。

#include
#include
#include
#include
#include
using namespace std;
const int maxn=160000+10;
int n;
int d[22222];

int time;

struct node
{
    int x,y,h,cost;
    bool operator <(const node &xx) const
    {
        return(cost>xx.cost);
    }
};

priority_queue que;

int hash[maxn],lon;
struct
{
    int x,y,cost,next;
}data[11111111];

void insert(struct node *p)
{
    inttmp=p->x+p->y;
    data[++lon].x=p->x;
    data[lon].y=p->y;
    data[lon].cost=p->h;
    data[lon].next=hash[tmp];
    hash[tmp]=lon;
}

int gcd(int a,int b)
{
    int tmp;
    while(a%b)
    {
        tmp=a%b;
        a=b;
        b=tmp;
    }
    return(b);
}

int check(int x,int y,int h)
{
    if(x<=0)return(0);
    if(y!=0)
    if(n%gcd(x,y)!=0)
    {
        return(0);
    }
    if(x==n||y==n)
    {
        printf("%d\n",h);
        exit(0);
    }
    if(x
    swap(x,y);

    if(x>n&&y>n) return(0);
    if(x>n*2)return(0);
    if(x>n&&y==0)return(0);
    if(x==y)return(0);

    for(intk=hash[x+y];k!=-1;k=data[k].next)
    {
        if(data[k].x==x&&data[k].y==y)
        {
            if(data[k].cost>h)
            {
                data[k].cost=h;
                return(1);
            }
            else
            return(0);
        }
    }

    return(1);
}

int cal(int x,int y)
{
    if(x==n)
    return (0);

    if(x
    return(d[x]);
    if(x>n)
    {
        int k=1;
        int tmp=x-n;
        while(y
        {
            k++;
            y<<=1;
        }
        return(k);
    }
}

void work(int x,int y,int h)
{
    if(x
    swap(x,y);
    struct node p;
    p.x=x;
    p.y=y;
    p.h=h;
    p.cost=h+cal(x,y);

    insert(&p);
    que.push(p);

}

int bfs()
{
    while(!que.empty())
    que.pop();

    memset(hash,-1,sizeof(hash));
    lon=0;
    struct node p;
    p.x=1;
    p.y=0;
    p.h=0;
    p.cost=p.h+cal(1,0);
    insert(&p);
    que.push(p);
    while(!que.empty())
    {
        intx=que.top().x,y=que.top().y,h=que.top().h+1,cost=que.top().cost;
        que.pop();

        if(x==n||y==n)
        return(cost);

        if(check(x+y,y,h))
        work(x+y,y,h);

        if(check(x,x+y,h))
        work(x,x+y,h);

        if(check(x+x,y,h))
        work(x+x,y,h);

        if(check(x,x+x,h))
        work(x,x+x,h);

        if(check(y+y,y,h))
        work(y+y,y,h);

        if(check(y+y,x,h))
        work(y+y,x,h);

        if(check(x-y,y,h))
        work(x-y,y,h);

        if(check(x,x-y,h))
        work(x,x-y,h);
    }
}

int main()
{
    scanf("%d",&n);
    for(inti=n,j,t=0;i>=1;i=j)
    {
        j=i/2,t++;
        for(int k=i-1;k>j;k--)
        d[k]=t+1;
        d[j]=t;
    }
    bfs();
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值