zoukankan      html  css  js  c++  java
  • A*算法

      A*算法其实就是估价函数来优化搜索什么的,关键是估价函数的构建。

    dij跑一遍bfs跑一遍即可。显然估价函数可以是由终点跑向各个点的最短路

    #include<bits/stdc++.h>
    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<ctime>
    #include<cstring>
    #include<string>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<vector>
    #include<map>
    #include<set>
    #include<algorithm>
    #include<bitset>
    #include<cmath>
    #include<cstdlib>
    #define INF 2147483642
    using namespace std;
    inline long long read()
    {
        long long 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;
    }
    inline void put(long long x)
    {
        if(x==0){putchar('0');putchar('
    ');return;}
        if(x<0)putchar('-'),x=-x;
        long long num=0;char ch[50];
        while(x)ch[++num]=x%10+'0',x/=10;
        while(num)putchar(ch[num--]);
        putchar('
    ');return;
    }
    priority_queue<pair<int,int> > q;
    const long long MAXN=10002;
    long long n,m,k;
    long long lin[MAXN],nex[MAXN],ver[MAXN],e[MAXN],len=0;
    long long clin[MAXN],cnex[MAXN],cver[MAXN],ce[MAXN],clen=0;
    int d[MAXN],vis[MAXN],ans[MAXN],cnt=0;
    void add(long long x,long long y,long long z)
    {
        ver[++len]=y;
        nex[len]=lin[x];
        lin[x]=len;
        e[len]=z;
    }
    void cadd(int x,int y,int z)
    {
        cver[++clen]=y;
        cnex[clen]=clin[x];
        clin[x]=clen;
        ce[clen]=z;
    }
    void dij(int x)
    {
        for(int i=1;i<=n;i++)d[i]=INF;
        memset(vis,0,sizeof(vis));
        q.push(make_pair(0,x));
        d[x]=0;
        while(q.size()!=0)
        {
            int te=q.top().second;
            q.pop();
            if(vis[te]==1)continue;
            vis[te]=1;
            for(int i=clin[te];i;i=cnex[i])
            {
                int tn=cver[i];
                if(d[tn]>d[te]+ce[i])
                {
                    d[tn]=d[te]+ce[i];
                    q.push(make_pair(-d[tn],tn));
                }
            }
        }
    }
    void bfs()
    {
        memset(ans,-1,sizeof(ans));
        q.push(make_pair(-d[n],n));
        while(q.size()!=0)
        {
            int te=q.top().second;
            int v=-q.top().first;
            q.pop();
            if(te==1)
            {
                ans[++cnt]=v-d[te];
                if(cnt==k)return;
                continue;
            }
            for(int i=lin[te];i;i=nex[i])
            {
                int tn=ver[i];
                q.push(make_pair(-(v-d[te]+e[i]+d[tn]),tn));
            }
        }
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        n=read();m=read();k=read();
        for(long long i=1;i<=m;i++)
        {
            long long x,y,z;
            x=read();y=read();z=read();
            add(max(x,y),min(x,y),z);
            cadd(min(x,y),max(x,y),z);
        }
        dij(1);
        bfs();
        for(int i=1;i<=k;i++)put(ans[i]);
        return 0;
    }
    View Code

    输出14 但是要注意细节和对第k短路的理解!(和上一道题相同的套路)

    #include<iostream>
    #include<iomanip>
    #include<cstdio>
    #include<ctime>
    #include<cstring>
    #include<string>
    #include<queue>
    #include<deque>
    #include<stack>
    #include<vector>
    #include<map>
    #include<set>
    #include<algorithm>
    #include<bitset>
    #include<cmath>
    #include<cstdlib>
    #define INF 2147483646
    using namespace std;
    inline 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;
    }
    inline void put(int x)
    {
        if(x==0){putchar('0');putchar('
    ');return;}
        if(x<0)putchar('-'),x=-x;
        int num=0;char ch[50];
        while(x)ch[++num]=x%10+'0',x/=10;
        while(num)putchar(ch[num--]);
        putchar('
    ');return;
    }
    priority_queue<pair<int,int> > q;
    const int MAXN=100002;
    int n,m;
    int lin[MAXN],nex[MAXN],ver[MAXN],e[MAXN],len=0;
    int clin[MAXN],cnex[MAXN],cver[MAXN],ce[MAXN],clen=0;
    int s1,s2,k,cnt=0,ans=-1;
    int g[MAXN],d[MAXN],vis[MAXN];
    void add(int x,int y,int z)
    {
        ver[++len]=y;
        nex[len]=lin[x];
        lin[x]=len;
        e[len]=z;
    }
    void cadd(int x,int y,int z)
    {
        cver[++clen]=y;
        cnex[clen]=clin[x];
        clin[x]=clen;
        ce[clen]=z;
    }
    void dij(int x)
    {
        for(int i=1;i<=n;i++)d[i]=INF;
        memset(vis,0,sizeof(vis));
        d[x]=0;q.push(make_pair(0,x));
        while(q.size()!=0)
        {
            int te=q.top().second;
            q.pop();
            if(vis[te]==1)continue;
            vis[te]=1;
            for(int i=clin[te];i;i=cnex[i])
            {
                int tn=cver[i];
                if(d[tn]>d[te]+ce[i])
                {
                    d[tn]=d[te]+ce[i];
                    q.push(make_pair(-d[tn],tn));
                }
            }
        }
    }
    void bfs()
    {
        if(s1==s2)k++;//敲黑板注意!细节!
        q.push(make_pair(-g[s1],s1));
        while(q.size()!=0)
        {
            int te=q.top().second;
            int v=-q.top().first;
            q.pop();
            if(te==s2)
            {
                cnt++;
                if(cnt==k){ans=v-g[te];return;}
            }
            for(int i=lin[te];i;i=nex[i])
            {
                int tn=ver[i];
                q.push(make_pair(-(v-g[te]+e[i]+g[tn]),tn));
            }
        }
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        n=read();m=read();
        for(int i=1;i<=m;i++)
        {
            int x,y,z;
            x=read();y=read();z=read();
            add(x,y,z);cadd(y,x,z);
        }
        s1=read();s2=read();k=read();
        dij(s2);
        if(d[s1]==INF){put(ans);return 0;}
        for(int i=1;i<=n;i++)g[i]=d[i];
        bfs();
        put(ans);
        return 0;
    }
    View Code

    这道题A*、其实更像IDA*(IDA:迭代加深)

    估计价值和具体细节不好想。代码之中。每次都和最优状态进行比较的出最优价值.

    #include<bits/stdc++.h>
    #include<iomanip>
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<ctime>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #include<deque>
    #include<set>
    #include<stack>
    #include<bitset>
    #include<map>
    #include<cstdlib>
    using namespace std;
    inline 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;
    }
    void put(int x)
    {
        if(x==0){putchar('0');putchar('
    ');return;}
        if(x<0)putchar('-'),x=-x;
        int num=0;char ch[50];
        while(x)ch[++num]=x%10+'0',x/=10;
        while(num)putchar(ch[num--]);
        putchar('
    ');return;
    }
    const int MAXN=6;
    int dx[9]={0,1,-1,1,-1,2,-2,2,-2};
    int dy[9]={0,2,-2,-2,2,1,-1,-1,1};
    int a[MAXN][MAXN]=
    {
        0,0,0,0,0,0,
        0,1,1,1,1,1,
        0,0,1,1,1,1,
        0,0,0,2,1,1,
        0,0,0,0,0,1,
        0,0,0,0,0,0,
    };
    int b[MAXN][MAXN];
    int t,n=5,m=5,s,s1;
    int flag=0,maxx=15;
    int ans=-1;
    char ch;
    int check()
    {
        int cnt=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                if(b[i][j]!=a[i][j])cnt++;
        }
        return cnt;//注意价值的估计
    }
    void dfs(int depth,int x,int y,int p)
    {
        if(flag==1)return;
        if(depth==p)
        {
            if(check()==0)ans=depth,flag=1;
            return;
        }
        for(int i=1;i<=8;i++)
        {
            int xx=x+dx[i];
            int yy=y+dy[i];
            if(xx<=0||yy<=0||xx>n||yy>m)continue;
            //int u=check();
            swap(b[x][y],b[xx][yy]);
            //if(u+depth-1<=p)dfs(depth+1,xx,yy,p);是等效的!
            if(check()+depth<=p)dfs(depth+1,xx,yy,p);
            //因为最后一步一定是check直接减2这里不需再+1.
            //对!就是因为最后一步是可以直接减2的加1的话限制了状态
            swap(b[x][y],b[xx][yy]);
        }
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        t=read();
        while(t--)
        {
            flag=0;ans=-1;
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                {
                    cin>>ch;
                    if(ch=='1')b[i][j]=1;
                    if(ch=='0')b[i][j]=0;
                    if(ch=='*')b[i][j]=2,s=i,s1=j;
                }
            //for(int i=1;i<=n;i++){for(int j=1;j<=m;j++)cout<<b[i][j]<<' ';cout<<endl;}
            for(int i=0;i<=maxx;i++){if(flag==0)dfs(0,s,s1,i);else break;}
            put(ans);
        }
        return 0;
    }

    如果不采用迭代加深搜索的话,直接爆搜只有50分。可能是我的只加了一个可行性剪枝。不够,不想思考剪枝了。

    爆搜代码(其实和迭代加深搜索差不多):

    #include<bits/stdc++.h>
    #include<iomanip>
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<ctime>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #include<deque>
    #include<set>
    #include<stack>
    #include<bitset>
    #include<map>
    #include<cstdlib>
    using namespace std;
    inline 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;
    }
    void put(int x)
    {
        if(x==0){putchar('0');putchar('
    ');return;}
        if(x<0)putchar('-'),x=-x;
        int num=0;char ch[50];
        while(x)ch[++num]=x%10+'0',x/=10;
        while(num)putchar(ch[num--]);
        putchar('
    ');return;
    }
    const int MAXN=6;
    int dx[9]={0,1,-1,1,-1,2,-2,2,-2};
    int dy[9]={0,2,-2,-2,2,1,-1,-1,1};
    int a[MAXN][MAXN]=
    {
        0,0,0,0,0,0,
        0,1,1,1,1,1,
        0,0,1,1,1,1,
        0,0,0,2,1,1,
        0,0,0,0,0,1,
        0,0,0,0,0,0,
    };
    int b[MAXN][MAXN];
    int t,n=5,m=5,s,s1;
    int flag=0,maxx=15;
    int ans=200,p=15;
    char ch;
    int check()
    {
        int cnt=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
                if(b[i][j]!=a[i][j])cnt++;
        }
        return cnt;//注意价值的估计
    }
    void dfs(int depth,int x,int y)
    {
        if(depth>p)return;
        if(depth>=ans)return;
        if(check()==0)ans=min(depth,ans),flag=1;
        for(int i=1;i<=8;i++)
        {
            int xx=x+dx[i];
            int yy=y+dy[i];
            if(xx<=0||yy<=0||xx>n||yy>m)continue;
            swap(b[x][y],b[xx][yy]);
            if(check()+depth<=p)dfs(depth+1,xx,yy);
            swap(b[x][y],b[xx][yy]);
        }
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        t=read();
        while(t--)
        {
            flag=0;ans=200;
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                {
                    cin>>ch;
                    if(ch=='1')b[i][j]=1;
                    if(ch=='0')b[i][j]=0;
                    if(ch=='*')b[i][j]=2,s=i,s1=j;
                }
            //for(int i=1;i<=n;i++){for(int j=1;j<=m;j++)cout<<b[i][j]<<' ';cout<<endl;}
            dfs(0,s,s1);
            if(flag==0)ans=-1;
            put(ans);
        }
        return 0;
    }
    View Code

    因为是一条路走到黑,所以没有限定层数的话会在不是正确解的地方浪费大量时间。

    所以迭代加深枚举答案的范围就有很大的优越性了。值得注意!

    这个就是和前面的搜索不太像了,原本我想的还是爆搜结果打脸了,估价函数是写出来了,但是显然dfs是不正确的因为不知道答案在第几层或者

    搜到一个状态却没有可以达到这个状态的最优解。什么的一大堆,判重也不好判,状态的携带也会浪费大量时间所以不能用dfs。

    优先bfs+A*即可。(不知道答案在第几层这样明显最优其实和IDA*差不多)

    但注意要加map判重,出现过的最优状态不必要以不优的状态再次出现。

    #include<bits/stdc++.h>
    #include<iomanip>
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<string>
    #include<cmath>
    #include<ctime>
    #include<algorithm>
    #include<queue>
    #include<vector>
    #include<deque>
    #include<set>
    #include<stack>
    #include<bitset>
    #include<map>
    #include<cstdlib>
    using namespace std;
    inline 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;
    }
    void put(int x)
    {
        if(x==0){putchar('0');putchar('
    ');return;}
        if(x<0)putchar('-'),x=-x;
        int num=0;char ch[50];
        while(x)ch[++num]=x%10+'0',x/=10;
        while(num)putchar(ch[num--]);
        putchar('
    ');return;
    }
    priority_queue<pair<int,pair<int,int> > > q;
    int a[4][4]=
    {
        0,0,0,0,
        0,1,2,3,
        0,8,0,4,
        0,7,6,5,
    };
    map<int,int>f;
    struct wy
    {
        int x,y;
    }t[10];
    int b[4][4],n=1,m=0,s1,s2,an,contrast;//vt 对比 使对照
    char ch[10];
    int dx[5]={0,1,-1,0,0};
    int dy[5]={0,0,0,1,-1};
    int len,ans,k1,k2;
    void prepare()
    {
        for(int i=1;i<=3;i++)
            for(int j=1;j<=3;j++)
                t[a[i][j]].x=i,t[a[i][j]].y=j;
    }
    int check(int d[][4])
    {
        int cnt=0;
        for(int i=1;i<=3;i++)
            for(int j=1;j<=3;j++)
            {
                cnt+=abs(t[d[i][j]].x-i)+abs(t[d[i][j]].y-j);
            }
        return cnt;
    }
    int compress(int c[][4])//压缩 vt
    {
        int cnt=0;
        for(int i=1;i<=3;i++)
            for(int j=1;j<=3;j++)
                cnt=cnt*10+c[i][j];
        return cnt;
    }
    void unfold(int cnt,int c[][4])//展开 vt
    {
        int u=3,u1=3;
        for(int i=1;i<=9;i++)
        {
            if(u1==0)u1=3,u--;
            if(cnt%10==0)k1=u,k2=u1;
            c[u][u1--]=cnt%10;
            cnt/=10;
        }
    }
    void bfs()
    {
        q.push(make_pair(-check(b),make_pair(check(b),an)));
        //cout<<an<<endl;cout<<check()<<endl;
        while(q.size()!=0)
        {
            int v=-q.top().first;
            int v1=q.top().second.first;
            int value=q.top().second.second;
            q.pop();v-=v1;
            //cout<<value<<endl;
            if(value==contrast){ans=v;return;}
            int d[4][4];
            unfold(value,d);
            for(int i=1;i<=4;i++)
            {
                int xx=k1+dx[i];
                int yy=k2+dy[i];
                if(xx<=0||yy<=0||xx>3||yy>3)continue;
                swap(d[k1][k2],d[xx][yy]);
                int sum=compress(d);
                if(f[sum]!=1)q.push(make_pair(-(v+1+check(d)),make_pair(check(d),sum)));
                f[sum]=1;
                swap(d[k1][k2],d[xx][yy]);
            }
            //for(int i=1;i<=3;i++){for(int j=1;j<=3;j++)cout<<d[i][j]<<' ';puts("");}
        }
    }
    int main()
    {
        //freopen("1.in","r",stdin);
        scanf("%s",ch+1);
        len=strlen(ch+1);
        for(int i=1;i<=len;i++)
        {
            if(m==3)m=0,n++;
            b[n][++m]=ch[i]-'0';
            if(ch[i]=='0')s1=n,s2=m;
            an=an*10+ch[i]-'0';
        }
        //cout<<an<<endl;
        prepare();
        contrast=compress(a);//cout<<contrast<<endl;
        //int d[4][4];
        //unfold(an,d);for(int i=1;i<=3;i++){for(int j=1;j<=3;j++)cout<<d[i][j]<<' ';puts("");}cout<<k1<<' '<<k2<<endl;
        //cout<<compress(d)<<endl;
        bfs();
        //cout<<check();
        //for(int i=1;i<=3;i++){for(int j=1;j<=3;j++)cout<<b[i][j]<<' ';puts("");}
        put(ans);
        return 0;
    }

  • 相关阅读:
    博客园-随笔分类批量修改
    【读书笔记】--少有人走的路①:心智成熟的旅程
    自定义菜单用例
    自定义菜单创建接口
    发送消息---被动回复用户消息
    接收消息----接收语音识别结果
    接收消息----接收事件推送
    微信开发入门教程
    Hadoop维护IPC链接
    Hadoop建立IPC连接和数据读写
  • 原文地址:https://www.cnblogs.com/chdy/p/10175772.html
Copyright © 2011-2022 走看看