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('\n');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('\n');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('\n');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('\n');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('\n');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('\n');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('\n');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('\n');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('\n');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('\n');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;
}

posted @ 2018-12-25 18:54  chdy  阅读(365)  评论(0编辑  收藏  举报