七、A*算法

A*star算法:

在bfs问题中,所有边权都是非负的,那么就可以使用启发函数来优化bfs过程。

特征:点数非常多

虽然bfs里没有剪枝操作,但是A*算法通过它独有的贪心,来做出一些预测,尽可能的使操作缩短。

178. 第K短路 - AcWing题库

 思路:首先把起点到终点的最短距离当作估值函数,因为无论其他怎么走到终点,都会使得路径长度>=最短距离。

#include<bits/stdc++.h>

using namespace std;

#define ll long long
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define PIII pair<int,PII>
const int N = 1010;
const int M = 2e5 + 10;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-8;

int n,m,S,T,K;
int h[N],rh[N],e[M],w[M],ne[M],idx;
int dist[N],cnt[N];
int st[N];
void add(int h[],int a,int b,int c)
{
    e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx ++; 
}
void dijstra()
{
    priority_queue<PII,vector<PII>,greater<PII> > heap;
    memset(dist,0x3f,sizeof dist);
    dist[T] = 0;
    heap.push({0,T});

    while(heap.size())
    {
        auto t = heap.top();
        heap.pop();

        int ver = t.second;
        if(st[ver]) continue;
        st[ver] = true;

        for(int i = rh[ver]; ~i; i = ne[i])
        {
            int j = e[i];
            if(dist[j] > dist[ver] + w[i])
            {
                dist[j] = dist[ver] + w[i];
                heap.push({dist[j],j});
            }
        }
    }
}
//我这里这个DIJ,意义是算最短路,S ----> K -----> T的K到T的值,因为把K -----> T是估值函数,(这样就没有比他更优的了且非常接近真实值)
int astar()
{
    priority_queue<PIII,vector<PIII>,greater<PIII> >heap;
    heap.push({dist[S],{0,S}});//估计值,真实值,点在哪
    //谁的d[u] + f[u] 为什么最优,因为真实值只会比他 >=
    //我要再去找S ----> K
    while(heap.size())
    {
        auto t = heap.top();
        heap.pop();

        int ver = t.second.second,distance = t.second.first;
        cnt[ver] ++;
        //cout << cnt[T] << endl;

        if(cnt[T] == K) return distance;
        for(int i = h[ver]; ~i; i = ne[i])
        {
            int j = e[i];
            if(cnt[j] < K)
            {
                heap.push({distance + w[i] + dist[j],{distance + w[i],j}});
                //d[u] + c + f[j]
            }
        }
    }
    return -1;
}
void solve()
{
    scanf("%d%d",&n,&m);
    memset(h,-1,sizeof h);
    memset(rh,-1,sizeof rh);

    for(int i = 0; i < m; i ++)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        add(h,a,b,c);
        add(rh,b,a,c);
    }
    scanf("%d%d%d",&S,&T,&K);
    //起点 == 终点舍去情况
    if(S == T) K ++;
    dijstra();
    printf("%d\n",astar());

}
int main()
{
    solve();



    system("pause");
    return 0;
}

179. 八数码 - AcWing题库

思路:

小结论:奇数码有解条件-------逆序对的数量必须是偶数

估值函数:每个点与目标距离的曼哈顿距离

#include<bits/stdc++.h>

using namespace std;

#define ll long long
#define PII pair<int, string>
#define PIS pair<char, string>

const int N = 1e6 + 10;
const int M = 2 * N;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double PI = acos(-1.0);
const double eps = 1e-8;
string str,ed,start;
unordered_map<string,int>dist;
unordered_map<string,PIS>pre;
int hr[4][2] = {{-1,0},{0,1},{1,0},{0,-1}};
int f(string s)
{
    int res = 0;
    for(int i = 0; i < 9; i ++)
        if(s[i] != 'x')
        {
            int t = s[i] - '1';
            res += abs(t / 3 - i / 3) + abs(t % 3 - i % 3);
        }
    return res;
}
void bfs(string start,string ed)
{
    priority_queue<PII,vector<PII>,greater<PII> > heap;
    dist[start] = 0;
    heap.push({f(start),start});
    char op[5] = {"urdl"};//对应的是坐标下的
    while(heap.size())
    {
        auto t = heap.top();
        heap.pop();

        string state = t.second;
        if(state == ed) break;

        int qwq = state.find('x');
        int x = qwq / 3;
        int y = qwq % 3;

        string source = state;
        for(int i = 0; i < 4; i ++)
        {
            int a = x + hr[i][0];
            int b = y + hr[i][1];

            if(a < 0 || a >= 3 || b < 0 || b >= 3) continue;
            state = source;
            swap(state[x * 3 + y],state[a * 3 + b]);
            if(!dist.count(state) || dist[state] > dist[source] + 1)
            {
                dist[state] = dist[source] + 1;
                pre[state] = {op[i],source};
                heap.push({dist[state] + f(state),state});
            }
        }
    }   
}
bool flag(string seq)
{
    //cout << seq << endl;
    int sum = 0;
    for(int i = 0; i < 8; i ++)
        for(int j = i + 1; j < 8; j ++)
        {
            if(seq[i] > seq[j]) sum ++;
        }
    if(sum % 2)
    {
        puts("unsolvable");
        return true;
    } 
    return false;
    
}
void solve()
{
    getline(cin,str);
    string seq;
    for(int i = 0; i < str.size(); i ++)
    {
        if(str[i] != ' ') start += str[i];
        if(str[i] != ' ' && str[i] != 'x') seq += str[i];
    }
    if(flag(seq)) return;
    ed = "12345678x";
 

    bfs(start,ed);


    string res;
    while(start != ed)
    {
        res += pre[ed].first;
        ed = pre[ed].second;
    }
    
    reverse(res.begin(),res.end());
    cout << res << endl;
}
int main()
{
    solve();



    system("pause");
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值