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;
    }

  • 相关阅读:
    POJ 3268 Silver Cow Party (Dijkstra)
    怒学三算法 POJ 2387 Til the Cows Come Home (Bellman_Ford || Dijkstra || SPFA)
    CF Amr and Music (贪心)
    CF Amr and Pins (数学)
    POJ 3253 Fence Repair (贪心)
    POJ 3069 Saruman's Army(贪心)
    POJ 3617 Best Cow Line (贪心)
    CF Anya and Ghosts (贪心)
    CF Fox And Names (拓扑排序)
    mysql8.0的新特性
  • 原文地址:https://www.cnblogs.com/chdy/p/10175772.html
Copyright © 2011-2022 走看看