USACO 2007 Dec Silver Mud Puddles bfs or A-star

標準做法是bfs暴搜
A*當然可過,標準A*尋路。
首先將圖轉成合適的形式,好看一點。
然後確定起止點。
下面代碼未完善,做題時會超時……
不過沒錯,也離正解不遠了。

#include <cstdio>
#include <cstring>
#include <set>
struct point 
{
    int x,y;
    int g,h,f;
    bool operator <(const point &s)const
    {
        return f<s.f;
    }
    point(){}
};
std::multiset <point> ope;
int a[1001][1001],fax[1001][1001],fay[1001][1001];
bool open[1001][1001],close[1001][1001];
int m,n,cnt;
int hx[]={0,1,0,-1},
    hy[]={-1,0,1,0};
point op,ed;
int gujia(point s)
{
    int tmp1=s.x-ed.x,tmp2=s.y-ed.y;
    if(tmp1<0)tmp1=-tmp1;
    if(tmp2<0)tmp2=-tmp2;
    return tmp1+tmp2;
}
void search(point st,point fl)
{
    st.g=0;
    st.h=gujia(st);
    st.f=st.g+st.h;
    open[st.x][st.y]=1;
    ope.insert(st);
//  printf("%d\n",st.f);
    while(ope.size()!=0)
    {
        std::multiset <point>::iterator it;
        it=ope.begin();
        point now=*it;
        ope.erase(it);
        open[now.x][now.y]=0;
        close[now.x][now.y]=1;
        if(now.x==fl.x&&now.y==fl.y)
            break;
        for(int i=0;i<4;i++)
        {
            point tmp;
            tmp.x=now.x+hx[i],tmp.y=now.y+hy[i];
            if(a[tmp.x][tmp.y]==-1||close[tmp.x][tmp.y])
                continue;
            tmp.g=now.g+1;
            tmp.h=gujia(tmp);
            tmp.f=tmp.g+tmp.h;
            if(!open[tmp.x][tmp.y])
            {
                open[tmp.x][tmp.y]=1;
                fax[tmp.x][tmp.y]=now.x,fay[tmp.x][tmp.y]=now.y;
                ope.insert(tmp);
            }   
            else
                for(std::multiset <point>::iterator j=ope.begin();j!=ope.end();j++)
                {
                    point tp=*j;
                    if(tp.x==tmp.x && tp.y==tmp.y && tp.g>tmp.g)
                    {
                        ope.erase(j);
                        fax[tmp.x][tmp.y]=now.x,fay[tmp.x][tmp.y]=now.y;
                        ope.insert(tmp);
                        break;
                    }
                }
                //就是這裏,就慢在這裏,這個遍歷我還沒想出方法省掉...
        }
    }
    int j=fl.x,k=fl.y;
    int o=j,i=k;
    for(;!(j==st.x&&k==st.y);j=fax[o][i],k=fay[o][i])
    {
        o=j,i=k;
//      printf("%d %d\n",o,i);
        cnt++;
    }
    return ;
}
int main()
{
    //懶得打了,請腦補
}
/*以下爲個人手出的樣例
in:
13 5
000000000000000000000000000
0     0     0     00000    
000 000 0 0 000 0000000 000
000     0 0     0   000 0 0
000 000 0 0 00000 0 000 0 0
000 0 0 0 0 00000 0   0 0 0
000 0 0 000 00000 0 0 0 0 0
000 0 0 000   000 0   0 0 0
000 0 0 000 0 000 000 0 0 0
        0   0     000     0
000000000000000000000000000

out:
32
*/

經過大爺的點撥改進出來一個map版,事實證明這個應該是沒錯的

#include <cstdio>
#include <cstring>
#include <set>
#include <map>
struct point 
{
    int x,y;
    int g,h,f;
    bool operator <(const point &s)const
    {
        return f<s.f;
    }
};
struct zb
{
    int x,y;
    bool operator <(const zb &s)const
    {
        return x==s.x?y<s.y:x<s.x;
    }
};
std::multiset <point> ope;
std::map <zb,std::multiset <point>::iterator> zbmap;
int a[1010][1010],fax[1010][1010],fay[1010][1010];
bool open[1010][1010],close[1010][1010];
int n,cnt;
int hx[]={0,1,0,-1},
    hy[]={-1,0,1,0};
point op,ed;
int gujia(point s)
{
    int tmp1=s.x-ed.x,tmp2=s.y-ed.y;
    if(tmp1<0)tmp1=-tmp1;
    if(tmp2<0)tmp2=-tmp2;
    return tmp1+tmp2;
}
void search(point st,point fl)
{
    st.g=0;
    st.h=gujia(st);
    st.f=st.g+st.h;
    open[st.x][st.y]=1;
    ope.insert(st);
    zb po;
    po.x=st.x,po.y=st.y;
    zbmap[po]=ope.begin();
//  printf("%d\n",st.f);
    while(ope.size()!=0)
    {
        std::multiset <point>::iterator it;
        it=ope.begin();
        point now=*it;
        ope.erase(it);
        open[now.x][now.y]=0;
        close[now.x][now.y]=1;
        if(now.x==fl.x&&now.y==fl.y)
            break;
        for(int i=0;i<4;i++)
        {
            point tmp;
            tmp.x=now.x+hx[i],tmp.y=now.y+hy[i];
            if(a[tmp.x][tmp.y]==-1||close[tmp.x][tmp.y]||
                tmp.x<0||tmp.x>1000||tmp.y<0||tmp.y>1000)
                continue;
            zb tp;
            tp.x=tmp.x,tp.y=tmp.y;
            tmp.g=now.g+1;
            tmp.h=gujia(tmp);
            tmp.f=tmp.g+tmp.h;
            if(!open[tmp.x][tmp.y])
            {
                open[tmp.x][tmp.y]=1;
                fax[tmp.x][tmp.y]=now.x,fay[tmp.x][tmp.y]=now.y;
                ope.insert(tmp);
                zbmap[tp]=ope.find(tmp);
            }
            else
            {
                point s=*zbmap[tp];
                if(s.g>tmp.g)
                {
                    ope.erase(zbmap[tp]);
                    ope.insert(tmp);
                    zbmap[tp]=ope.find(tmp);
                }
            }
        }
    }
    int j=fl.x,k=fl.y;
    int o=j,i=k;
    for(;!(j==st.x&&k==st.y);j=fax[o][i],k=fay[o][i])
    {
        o=j,i=k;
//      printf("!%d %d\n",o,i);
        cnt++;
    }
    return ;
}
int main()
{
    memset(a,0,sizeof(a));
    scanf("%d%d%d",&op.x,&op.y,&n);
    ed.x=500,ed.y=500;
    op.x+=500;op.y+=500;
    bool flag=1;
    for(int i=1;i<=n;i++)
    {
        int nx,ny;
        scanf("%d%d",&nx,&ny);
        a[nx+500][ny+500]=-1;
    }
    search(op,ed);
    printf("%d",cnt);
    return 0;
}

那麼我們來看一下效率
在jdoj上同一道題
上面那個是我
可見
A*比一般的bfs快
但空間佔用大
可以嘗試寫IDA*
有效縮小空間

發佈了35 篇原創文章 · 獲贊 5 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章