leetcode——启发式搜索

847. 访问所有节点的最短路径 - 力扣(LeetCode)

一个很重要的优化,起点一定是连接节点个数最少的,这样保证了路径最短

class Solution
{
public:
    struct state
    {
        int now;
        int loc;
        int dist; //这是比较用的dist,dis + astar
        //返回值是bool类型,重载运算符<, 右边参数为不能修改的引用,这个函数不会修改结构体的值
        bool operator<(const state &rhs) const
        {
            return dist > rhs.dist;
        }
    };
    int astar(int loc)
    {
        // 1的数量表示还需要去哪些点
        int res = 0;
        while (loc)
        {
            loc -= (loc & -loc);
            res++;
        }
        return res;
    }
    int shortestPathLength(vector<vector<int>> &graph)
    {
        int n = graph.size();
        int ans = 0x3f3f3f3f;
        int mi = 0x3f3f3f3f;
        for(auto &p: graph)
            mi=min(mi, (int)p.size());

        unordered_map<int, unordered_map<int, int>> dist;
        priority_queue<state, vector<state>> q;
        for (int i = 0; i < n; i++)
        {
            //起点i
            if(graph[i].size() != mi) continue; 
            int loc = ((1 << n) - 1) ^ (1 << i);
            dist[i][loc] = 0;
            q.push({i, loc, n - 1});
        }
            while (q.size())
            {
                auto t = q.top();
                q.pop();
                int u = t.now;
                int d = astar(t.loc);
                if(d > astar(t.loc) + dist[u][t.loc]) continue;
  
                if (astar(t.loc) == 0)
                {
                    ans = min(ans, t.dist);
                    break;
                }
                for (int j = 0; j < graph[u].size(); j++)
                {
                    int nx = graph[u][j];
                    int nloc = t.loc;
                    if (t.loc & (1 << nx))
                        nloc ^= (1 << nx);
                    //如果nx位置没有走过,更新nloc
                    // if(st[nx][nloc]) continue;
                    if (!dist.count(nx) || !dist[nx].count(t.loc) || dist[nx][nloc] > dist[u][t.loc] + 1)
                    {
                        dist[nx][nloc] = dist[u][t.loc] + 1;
                        q.push({nx, nloc, dist[nx][nloc] + astar(nloc)});
                    }
                }
            }
        
        return ans;
    }
};

127. 单词接龙 - 力扣(LeetCode)

class Solution
{
public:
    typedef pair<int,int> PII;
    bool edgeif(string a, string b)
    {
        unordered_map<char, int> mp;
        if (a == b)
            return true;
        bool flag = false;
        for (int i = 0; i < a.size(); i++)
        {
            if (a[i] != b[i] && !flag)
            {
                flag = true;
            }
            else if(a[i] != b[i] && flag)
                return false;
        }
        return true;
    }
    int astar(int _a, int _end, vector<string> &wordList)
    {
        string a = wordList[_a];
        string end = wordList[_end];
        if (a.size() != end.size())
            return 0x3f3f3f3f;
        int res = 0;
        for (int i = 0; i < a.size(); i++)
        {
            if (a[i] != end[i])
                res++;
        }
        return res;
    }
    int ladderLength(string beginWord, string endWord, vector<string> &wordList)
    {
        wordList.push_back(beginWord);
        if (find(wordList.begin(), wordList.end(), endWord) == wordList.end())
            return 0;
        wordList.push_back(endWord);
        int n = wordList.size();
       
        unordered_map<string, int> mp;
        for(int i = 0; i < wordList.size(); i ++) mp[wordList[i]] = i;
       
        int dist[n];
        bool st[n];
        memset(dist, 0x3f3f3f3f, sizeof(dist));
        memset(st, 0, sizeof(st));
        dist[n - 2] = 0;
        st[n - 2] = true;
        priority_queue<PII, vector<PII>, greater<PII>> q;
        q.push({astar(n - 2, n - 1, wordList), n - 2});
        while (q.size())
        {
            auto t = q.top();
            q.pop();
            int u = t.second;
            if(u == n - 1) break;
            st[u] = false;
            
            for(int i = 0; i < 26; i ++ )
            for(int j = 0; j < wordList[u].size(); j ++)
            {
                string now = wordList[u];
                if(now[j] != 'a' + i)
                {
                    now[j] = 'a' + i;
                }
                if(!mp.count(now))
                continue;
                int to = mp[now];
                if (st[to])
                    continue;
                int d_a = astar(to, n - 1, wordList);
                if (dist[to] > dist[u] + 1 )
                {
                    dist[to] = dist[u] + 1;
                    st[to] = true;
                    q.push({dist[to] + d_a, to});
                }
            }
        }
        if (dist[n - 1] >= 0x3f3f3f3f)
            return 0;
        return dist[n - 1] + 1;
    }
};

752. 打开转盘锁 - 力扣(LeetCode)

class Solution
{
public:
    //  0 1 2 3 4 5 6 7 8 9
    typedef pair<int, string> PIS;
    int astar(string a, string target)
    {
        int res = 0;
        for (int i = 0; i < a.size(); i++)
        {
            res += min((a[i] - target[i] + 10) % 10, (-a[i] + target[i] + 10) % 10);
        }
        return res;
    }
    int openLock(vector<string> &deadends, string target)
    {
        if(target == "0000") return 0;
        //每个数字可以有两个旋转方式,每次可以选择一个位置旋转,不能旋转到死亡数字
        priority_queue<PIS, vector<PIS>, greater<PIS>> q;
        unordered_map<string, bool> st;
        unordered_map<string, int> dist;
        for (auto p : deadends)
            st[p] = true; //标记死亡状态
        if (!st["0000"])
        {
            q.push({astar("0000", target), "0000"}); //初始状态
            st["0000"] = true;
        }
        bool flag = false;
        while (!q.empty())
        {
            auto u = q.top();
            string t = u.second;
            st[t] = false;
            q.pop();
            if (t == target)
            {
                break;
            }
            for (int i = 0; i < 4; i++) //找一个位置
            {
                string ne = t;
                ne[i] = (t[i] - '0' + 1) % 10 + '0';
                if (!st[ne])
                {
                    if (!dist.count(ne) || dist[ne] > dist[t] + 1)
                    {
                        dist[ne] = dist[t] + 1;
                        st[ne] = true;
                        q.push({dist[ne] + astar(ne, target), ne});
                    }
                }
                ne[i] = (t[i] - '0' - 1 + 10) % 10 + '0';
                if (!st[ne])
                {
                    if (!dist.count(ne) || dist[ne] > dist[t] + 1)
                    {
                        dist[ne] = dist[t] + 1;
                        st[ne] = true;
                        q.push({dist[ne] + astar(ne, target), ne});
                    }
                }
            }
        }
        if (dist.count(target))
            return dist[target];
        else
            return -1;
    }
};

773. 滑动谜题 - 力扣(LeetCode)

#define x first
#define y second
class Solution {
public:
    string end = "123450";
    int dx[4] = {0, 0, 1, -1}, dy[4] = {1, -1, 0, 0};
    typedef pair<int, string> PIS;
    int f(string s)
    {
        int res = 0;
        for(int i = 0; i < s.size(); i ++ )
        if(s[i] != '0')
        {
            int p = s[i] - '1';
            res += abs(i / 3 - p / 3) + abs(i % 3 - p % 3);
        }
        return res;
    }
    int bfs(string state)
    {
        unordered_map <string, int> dist;
        priority_queue <PIS, vector<PIS>, greater<PIS>> q;
        unordered_map <string, bool> st;
        st[state] = true;
        q.push({f(state), state});//将初始状态入栈
        dist[state] = 0;
        while(q.size())
        {
            auto t = q.top();
            q.pop();
            string s = t.y;
            if(s == end) break;
            st[s] = false;
            int x, y;
            for(int i = 0; i < 6; i ++ )//找到0的位置
            {
                if(s[i] == '0')
                {
                    x = i / 3;
                    y = i % 3;
                    break;
                }
            }
            for(int i = 0; i < 4; i ++ )//和上下左右交换
            {
                int nx = x + dx[i], ny = y + dy[i];
                if(nx < 0 || ny < 0 || nx > 1 || ny > 2) continue;//两行三列
                string source = s;
                swap(source[x * 3 + y], source[nx * 3 + ny]);
                if(st[source]) continue;
                if(!dist.count(source) || dist[source] > dist[s] + 1)//dist是无穷大或者是比s + 1大
                {
                    dist[source] = dist[s] + 1;
                    q.push({f(source) + dist[source], source});
                }
            }
        }
        return dist[end];
    }
    int slidingPuzzle(vector<vector<int>>& board) {
        //A* 多次入栈,终点出栈只能确定终点的最短路径
        //判断是否有解
        string start;
        for(auto &t : board)
        for(auto &x : t)
            start += x + '0';
        int cnt = 0;
        for(int i = 0; i < 6; i ++ )
        for(int j = i + 1; j < 6; j ++ )
        {
            if(start[i] != '0' && start[j] != '0' && start[j] < start[i]) cnt ++;
        }
        if(cnt % 2) return -1;
        else return bfs(start);
    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值