zoukankan      html  css  js  c++  java
  • AcWing算法提高课【第二章搜索】多源BFS、最小步数模型、双端队列广搜、双向搜索、A*

    多源BFS

    173. 矩阵距离 

    题目:

    给定一个 N 行 M 列的 01矩阵 A,A[i][j] 与 A[k][l] 之间的曼哈顿距离定义为:
    
     
    
    dist(A[i][j],A[k][l])=|i−k|+|j−l|
     
    
    输出一个 N 行 M 列的整数矩阵 B,其中:
    
     
    
    B[i][j]=min1≤x≤N,1≤y≤M,A[x][y]=1dist(A[i][j],A[x][y])
     
    
    输入格式
    第一行两个整数 N,M。
    
    接下来一个 N 行 M 列的 01 矩阵,数字之间没有空格。
    
    输出格式
    一个 N行 M 列的矩阵 B,相邻两个整数之间用一个空格隔开。
    
    数据范围
    1≤N,M≤1000
    
    输入样例:
    3 4
    0001
    0011
    0110
    输出样例:
    3 2 1 0
    2 1 0 0
    1 0 0 1
    

      

    分析:

    就是求0所在的位置,到1的最近的曼哈顿距离。

    我们可以将所有的1放入队列中,表示bfs的第一层,然后搜下去。

    代码:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 
     5 using namespace std;
     6 
     7 typedef pair<int, int> PII;
     8 
     9 #define x first
    10 #define y second
    11 
    12 const int N = 1010;
    13 
    14 int n, m;
    15 char g[N][N];
    16 PII q[N * N];
    17 int d[N][N];
    18 int hh, tt;
    19 
    20 void bfs()
    21 {
    22     int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
    23     while (hh <= tt)
    24     {
    25         PII t = q[++ hh];
    26         
    27         for (int i = 0; i < 4; i ++ )
    28         {
    29             int x = t.x + dx[i], y = t.y + dy[i];
    30             if (x < 0 || x >= n || y < 0 || y >= m) continue;
    31             if (g[x][y] == '1') continue;
    32             if (d[x][y] != -1) continue;
    33             
    34             d[x][y] = d[t.x][t.y] + 1;
    35             q[++ tt] = {x, y};
    36         }
    37     }
    38 }
    39 int main()
    40 {
    41     scanf("%d%d", &n, &m);
    42     for (int i = 0; i < n; i ++ ) scanf("%s", g[i]);
    43     
    44     memset(d, -1, sizeof d);
    45     
    46     for (int i = 0; i < n; i ++ ) 
    47         for (int j = 0; j < m; j ++ )
    48             if (g[i][j] == '1') 
    49             {
    50                 q[ ++ tt] = {i, j};
    51                 d[i][j] = 0;
    52             }
    53             
    54     bfs();
    55     
    56     for (int i = 0; i < n; i ++ ) 
    57     {
    58         for (int j = 0; j < m; j ++ ) 
    59             printf("%d ", d[i][j]);
    60         puts("");
    61     }
    62         
    63     
    64     return 0;
    65 }
    View Code

    最小步数模型

     1107. 魔板

    题目:

    Rubik 先生在发明了风靡全球的魔方之后,又发明了它的二维版本——魔板。
    
    这是一张有 8 个大小相同的格子的魔板:
    
    1 2 3 4
    8 7 6 5
    我们知道魔板的每一个方格都有一种颜色。
    
    这 8 种颜色用前 8 个正整数来表示。
    
    可以用颜色的序列来表示一种魔板状态,规定从魔板的左上角开始,沿顺时针方向依次取出整数,构成一个颜色序列。
    
    对于上图的魔板状态,我们用序列 (1,2,3,4,5,6,7,8) 来表示,这是基本状态。
    
    这里提供三种基本操作,分别用大写字母 A,B,C 来表示(可以通过这些操作改变魔板的状态):
    
    A:交换上下两行;
    B:将最右边的一列插入到最左边;
    C:魔板中央对的4个数作顺时针旋转。
    
    下面是对基本状态进行操作的示范:
    
    A:
    
    8 7 6 5
    1 2 3 4
    B:
    
    4 1 2 3
    5 8 7 6
    C:
    
    1 7 2 4
    8 6 3 5
    对于每种可能的状态,这三种基本操作都可以使用。
    
    你要编程计算用最少的基本操作完成基本状态到特殊状态的转换,输出基本操作序列。
    
    注意:数据保证一定有解。
    
    输入格式
    输入仅一行,包括 8 个整数,用空格分开,表示目标状态。
    
    输出格式
    输出文件的第一行包括一个整数,表示最短操作序列的长度。
    
    如果操作序列的长度大于0,则在第二行输出字典序最小的操作序列。
    
    数据范围
    输入数据中的所有数字均为 1 到 8 之间的整数。
    
    输入样例:
    2 6 8 4 5 7 3 1
    输出样例:
    7
    BCABCCB
    

      

    分析:

    还是最短路模板,这次我们不是将路放到了棋盘上,而是变成了状态的变化,一个思想。

    代码:

      1 #include <bits/stdc++.h>
      2 
      3 using namespace std;
      4 
      5 unordered_map<string, int> dist;//表示到当前字符的距离
      6 unordered_map<string, pair<char, string> > pre;//标记路径
      7 
      8 char g[2][4];
      9 
     10 void sets(string s)
     11 {
     12     for (int i = 0; i < 4; i ++ ) g[0][i] = s[i];
     13     for (int i = 7, j = 0; i >= 4; i -- , j ++ ) g[1][j] = s[i];
     14 }
     15 
     16 string get()
     17 {
     18     string s; 
     19     for (int i = 0; i < 4; i ++ ) s += g[0][i];
     20     for (int i = 3; i >= 0; i -- ) s += g[1][i];
     21     return s;
     22 }
     23 
     24 string get0(string s)
     25 {
     26     sets(s);
     27     //兑换两行
     28     swap(g[0], g[1]);
     29     
     30     return get();
     31 }
     32 
     33 string get1(string s)
     34 {
     35     sets(s);
     36     //将最后一列放到第一列前面
     37     char c1 = g[0][3], c2 = g[1][3];
     38     for (int i = 0; i < 2; i ++ ) 
     39         for (int j = 3; j >= 1; j -- ) 
     40             g[i][j] = g[i][j - 1];
     41     g[0][0] = c1, g[1][0] = c2;
     42     return get();
     43 }
     44 
     45 string get2(string s)
     46 {
     47     sets(s);
     48     //将中间的四个数顺时针旋转90度
     49     swap(g[0][1], g[1][1]);
     50     swap(g[1][1], g[1][2]);
     51     swap(g[1][2], g[0][2]);
     52     return get();
     53 }
     54 void bfs(string start, string end)
     55 {
     56     if (start == end) return;
     57     
     58     queue<string> q;
     59     q.push(start);
     60     dist[start] = 0;
     61     
     62     while (q.size())
     63     {
     64         string t = q.front();
     65         q.pop();
     66         
     67         string m[3];
     68         m[0] = get0(t);
     69         m[1] = get1(t);
     70         m[2] = get2(t);
     71         
     72         for (int i = 0; i < 3; i ++ ) 
     73             if (!dist.count(m[i]))
     74             {
     75                 dist[m[i]] = dist[t] + 1;
     76                 pre[m[i]] = {'A' + i, t};
     77                 q.push(m[i]);
     78                 if (m[i] == end) return;
     79             }
     80     }
     81     return;
     82 }
     83 
     84 int main()
     85 {
     86     string start, end;
     87     for (int i = 0; i < 8; i ++ )
     88     {
     89         char c = i + '1';
     90         start += c;
     91     }
     92     
     93     for (int i = 1; i <= 8; i ++ )
     94     {
     95         int x; cin >> x;
     96         end += x + '0';
     97     }
     98     
     99     bfs(start, end);
    100     
    101     cout << dist[end] << "
    ";
    102     
    103     string s;
    104     while (start != end)
    105     {
    106         s += pre[end].first;
    107         end = pre[end].second;
    108     }
    109     reverse(s.begin(), s.end());
    110     if (s.size()) cout << s << "
    ";
    111     
    112     return 0;
    113 }
    View Code

     双端队列模型

    题目:175. 电路维修

    达达是来自异世界的魔女,她在漫无目的地四处漂流的时候,遇到了善良的少女翰翰,从而被收留在地球上。

    翰翰的家里有一辆飞行车。

    有一天飞行车的电路板突然出现了故障,导致无法启动。

    电路板的整体结构是一个 R 行 C 列的网格(R,C500),如下图所示。

    电路.png

    每个格点都是电线的接点,每个格子都包含一个电子元件。

    电子元件的主要部分是一个可旋转的、连接一条对角线上的两个接点的短电缆。

    在旋转之后,它就可以连接另一条对角线的两个接点。

    电路板左上角的接点接入直流电源,右下角的接点接入飞行车的发动装置。

    达达发现因为某些元件的方向不小心发生了改变,电路板可能处于断路的状态。

    她准备通过计算,旋转最少数量的元件,使电源与发动装置通过若干条短缆相连。

    不过,电路的规模实在是太大了,达达并不擅长编程,希望你能够帮她解决这个问题。

    注意:只能走斜向的线段,水平和竖直线段不能走。

    输入格式

    输入文件包含多组测试数据。

    第一行包含一个整数 TT,表示测试数据的数目。

    对于每组测试数据,第一行包含正整数 R 和 C,表示电路板的行数和列数。

    之后 R 行,每行 C 个字符,字符是"/"""中的一个,表示标准件的方向。

    输出格式

    对于每组测试数据,在单独的一行输出一个正整数,表示所需的缩小旋转次数。

    如果无论怎样都不能使得电源和发动机之间连通,输出 NO SOLUTION

    数据范围

    1R,C500,
    1T5

    输入样例:

    1
    3 5
    \/\
    \///
    /\\
    

    输出样例:

    1
    

    样例解释

    样例的输入对应于题目描述中的情况。

    只需要按照下面的方式旋转标准件,就可以使得电源和发动机之间连通。

    电路2.png

    分析:

    题目使用双端队列来做BFS,但是,用了双端队列后,因为为了满足二段性,将权值为0的查到队首,将权值为1的点插入到了队尾,这也就导致了,一个点有可能会被更新多次,这很像对优化版的dijkstra算法,巴拉巴拉~~~

    这不是自己做出的,也没有吃透这个算法,还要再多次做做这个题

    代码:

    #include <cstdio>
    #include <cstring>
    #include <deque>
    
    using namespace std;
    
    typedef pair<int, int> PII;
    
    #define x first
    #define y second
    
    const int N = 510;
    
    int n, m;
    char g[N][N];
    int dist[N][N];
    bool st[N][N];
    
    int bfs()
    {
        memset(dist, 0x3f, sizeof dist);
        memset(st, 0, sizeof st);
        dist[0][0] = 0;
        deque<PII> q;
        q.push_back({0, 0});
        
        int dx[4] = {-1, -1, 1, 1}, dy[4] = {-1, 1, 1, -1};
        int ix[4] = {-1, -1, 0, 0}, iy[4] = {-1, 0, 0, -1};
        char c[10] = "\/\/";
        
        while (q.size())
        {
            PII t = q.front();
            q.pop_front();
            
            if (st[t.x][t.y]) continue;
            st[t.x][t.y] = true;
            for (int i = 0; i < 4; i ++ )
            {
                int x = t.x + dx[i], y = t.y + dy[i];
                int cx = t.x + ix[i], cy = t.y + iy[i];
                
                if (x < 0 || x > n || y < 0 || y > m) continue;
                if (st[x][y]) continue;
                
                int w = g[cx][cy] != c[i];
                int d = dist[t.x][t.y] + w;
                if (dist[x][y] > d)
                {
                    dist[x][y] = d;
                    if (w)
                    {
                        q.push_back({x, y});
                    }
                    else 
                    {
                        q.push_front({x, y});
                    }
                }
            }
        }
        return dist[n][m];
    }
    
    void work()
    {
        scanf("%d%d", &n, &m);
        for (int i = 0; i < n; i ++ ) scanf("%s", g[i]);
        
        if ((n + m) & 1) puts("NO SOLUTION");
        else printf("%d
    ", bfs());
        
        return;
    }
    
    int main()
    {
        int T; scanf("%d", &T);
        while (T -- )
        {
            work();
        }
        return 0;
    }

    双向搜索【双向广搜一般用于最小步数模型,因为每层的状态会是非常庞大的,一般不用与其他,如最短路模型】:

    双向广搜,每次选择当前队列元素较少的扩展
    

      

    190. 字串变换

    题目:

    已知有两个字串 A, B 及一组字串变换的规则(至多 6 个规则):
    
    A1→B1
    A2→B2
    …
    
    规则的含义为:在 A 中的子串 A1 可以变换为 B1、A2 可以变换为 B2…。
    
    例如:A=abcd B=xyz
    
    变换规则为:
    
    abc → xu ud → y y → yz
    
    则此时,A 可以经过一系列的变换变为 B,其变换的过程为:
    
    abcd → xud → xy → xyz
    
    共进行了三次变换,使得 A 变换为 B。
    
    输入格式
    输入格式如下:
    
    A B
    A1 B1
    A2 B2
    … …
    
    第一行是两个给定的字符串 A 和 B。
    
    接下来若干行,每行描述一组字串变换的规则。
    
    所有字符串长度的上限为 20。
    
    输出格式
    若在 10 步(包含 10 步)以内能将 A 变换为 B ,则输出最少的变换步数;否则输出 NO ANSWER!。
    
    输入样例:
    abcd xyz
    abc xu
    ud y
    y yz
    输出样例:
    3
    

    分析:

    其实一开始像的就是和八数码一样做,用map将将所有起点存进去,然后做宽搜的
    但是,这个题要搜的状态太庞大了,字符串长度为20, 最多会有6中变化,那么我们第一层状态的维护120中,搜索10层,这就是120的10次方,大的要死,我暴力写,直接MLE内存超限了。
    所以,题解为双向搜索。从出状态往末状态搜索,同时从末状态向着初状态搜索。 

    代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    #include <unordered_map>
    
    using namespace std;
    
    const int N = 100010;
    
    int len;
    string a[N], b[N];
    unordered_map<string, int> d1, d2;
    
    int bfs(string start, string end)
    {
        queue<string> q1, q2;
        q1.push(start), d1[start] = 0;
        q2.push(end), d2[end] = 0;
        
        //当q1和q2有一个队列元素被扩展完的时候,说明两个队列扩展的元素没有交集,可以推出循环了
        while (q1.size() && q2.size())
        {
            //如果q1队列里面的元素较少的话,先搜索q1
            int s = q1.size(), t = q2.size();
            // if (q1.size() <= q2.size())
            if (s <= t)
            {
                string x = q1.front();
                q1.pop();
                // cout << "q1:" << x << "
    ";
                for (int i = 0; i < x.size(); i ++ ) 
                    for (int j = 0; j < len; j ++ ) 
                        if (x.substr(i, a[j].size()) == a[j]) 
                        {   
                            string y = x.substr(0, i) + b[j] + x.substr(i + a[j].size());
                            // cout << "q1: " << x << "||" << a[j] << "||" << y << "
    ";
                            if (d2.count(y)) return d2[y] + d1[x] + 1; 
                            if (!d1.count(y))
                            {
                                d1[y] = d1[x] + 1;
                                q1.push(y);
                            }
                        }
            }
            else 
            {
                string x = q2.front();
                q2.pop();
                // cout << "q2:" << x << "
    "; 
                for (int i = 0; i < x.size(); i ++ ) 
                    for (int j = 0; j < len; j ++ ) 
                        if (x.substr(i, b[j].size()) == b[j])
                        {
                            string y = x.substr(0, i) + a[j] + x.substr(i + b[j].size());
                            // cout << "q2: " << x << "||" << a[j] << "||" << y << "
    ";
                            if (d1.count(y)) return d1[y] + d2[x] + 1;                       
                            if (!d2.count(y))
                            {
                                d2[y] = d2[x] + 1;
                                q2.push(y);
                            }
                        }
            }
        }
        
        return 11;
    }
    
    int main()
    {
        string start, end;
        cin >> start >> end;
        
        while (cin >> a[len] >> b[len]) len ++;
        
        int ans = bfs(start, end);
        // cout << ans << "
    ";
        if (ans < 0 || ans > 10) puts("NO ANSWER!");
        else printf("%d
    ", ans);
        return 0;
    }
    

    A*

    起点到当前实际距离,d[x] 
    当前点到终点的预估函数,f[x]
    当前点到终点的真是距离,g[x]
    优先队列优化的BFS或者叫堆优化版的dijkstra算法。   
    A*算法一定能保证终点在第一次出队时是最优的,但是不能保证其他点一定是最优的

    179. 八数码

    在一个 3×3 的网格中,1∼8 这 8 个数字和一个 X 恰好不重不漏地分布在这 3×3 的网格中。
    
    例如:
    
    1 2 3
    X 4 6
    7 5 8
    在游戏过程中,可以把 X 与其上、下、左、右四个方向之一的数字交换(如果存在)。
    
    我们的目的是通过交换,使得网格变为如下排列(称为正确排列):
    
    1 2 3
    4 5 6
    7 8 X
    例如,示例中图形就可以通过让 X 先后与右、下、右三个方向的数字交换成功得到正确排列。
    
    交换过程如下:
    
    1 2 3   1 2 3   1 2 3   1 2 3
    X 4 6   4 X 6   4 5 6   4 5 6
    7 5 8   7 5 8   7 X 8   7 8 X
    把 X 与上下左右方向数字交换的行动记录为 u、d、l、r。
    
    现在,给你一个初始网格,请你通过最少的移动次数,得到正确排列。
    
    输入格式
    输入占一行,将 3×3 的初始网格描绘出来。
    
    例如,如果初始网格如下所示:
    
    1 2 3 
    x 4 6 
    7 5 8 
    则输入为:1 2 3 x 4 6 7 5 8
    
    输出格式
    输出占一行,包含一个字符串,表示得到正确排列的完整行动记录。
    
    如果答案不唯一,输出任意一种合法方案即可。
    
    如果不存在解决方案,则输出 unsolvable。
    
    输入样例:
    2  3  4  1  5  x  7  6  8 
    输出样例
    ullddrurdllurdruldr 

    分析:

    代码:

    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #include <unordered_map>
    #include <queue>
    
    using namespace std;
    
    typedef pair<int, string> PIS;
    
    #define x first
    #define y second
    
    //A*(将dist和f)
    
    int f(string s)//当前状态s到达最终状态end的曼哈顿距离
    {
        int ans = 0;
        for (int i = 0; i < 9; i ++ ) 
            if (s[i] != 'x')
            {
                int t = s[i] - '1';
                ans += abs(i / 3 - t / 3) + abs(i % 3 - t % 3);
            }
        
        return ans;
    }
    
    string bfs(string start, string end)
    {
        int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};    
        char c[] = "urdl";
        
        unordered_map<string, int> dist;
        unordered_map<string, pair<string, char>> pre;
        
        priority_queue<PIS, vector<PIS>, greater<PIS>> q;
        
        q.push({f(start), start});
        
        while (q.size())
        {
            PIS t = q.top();
            q.pop();
            
            string state = t.y;
            
            if (state == end) break;
            
            int x, y; 
            // cout << state.size() << "
    ";
            for (int i = 0; i < state.size(); i ++ ) 
                if (state[i] == 'x') 
                {
                    x = i / 3, y = i % 3;
                    // cout << state[i] << "  " << x << "  " << y << "
    ";
                }
            // cout << state << "
    ";
            for (int i = 0; i < 4; i ++ )
            {
                int a = x + dx[i], b = y + dy[i];
                // cout << a << " " << b << "
    ";
                if (a < 0 || a >= 3 || b < 0 || b >= 3) continue;
                string s = state;
                swap(s[3 * x + y], s[3 * a + b]);
                // cout << s << "||" << state << "
    ";
                if (!dist[s] || dist[s] > dist[state] + 1) 
                {
                    dist[s] = dist[state] + 1;
                    pre[s] = {state, c[i]};
                    q.push({dist[s] + f(s), s});
                }
            }
        }
        
        // cout << "start: " << start << "
    " << "end: " << end << '
    ';
        // cout << "end.x: " << pre[end].x << " " << "end.y: " << pre[end].y << "
    ";
        
        string res;
        while (end != start)
        {
            res += pre[end].y;
            end = pre[end].x;
        }
        reverse(res.begin(), res.end());
        
        return res;
    }
    
    int main()
    {
        string start, end, sep;
        end = "12345678x";
        
        char c;
        for (int i = 0; i < 9; i ++ )
        {
            cin >> c;
            start += c;
            if (c != 'x') sep += c;
        }
        
        int cnt = 0;
        for (int i = 0; i < sep.size(); i ++ )
            for (int j = i + 1; j < sep.size(); j ++ )
                if (sep[i] > sep[j]) cnt ++;
        
        // cout << cnt << "
    ";
        if (cnt % 2 == 0) cout << bfs(start, end) << "
    ";
        else puts("unsolvable");
        
        return 0;
    }
    

      

    178. 第K短路

    题目:

    给定一张 N 个点(编号 1,2…N),M 条边的有向图,求从起点 S 到终点 T 的第 K 短路的长度,路径允许重复经过点或边。
    
    注意: 每条最短路中至少要包含一条边。
    
    输入格式
    第一行包含两个整数 N 和 M。
    
    接下来 M 行,每行包含三个整数 A,B 和 L,表示点 A 与点 B 之间存在有向边,且边长为 L。
    
    最后一行包含三个整数 S,T 和 K,分别表示起点 S,终点 T 和第 K 短路。
    
    输出格式
    输出占一行,包含一个整数,表示第 K 短路的长度,如果第 K 短路不存在,则输出 −1。
    
    数据范围
    1≤S,T≤N≤1000,
    0≤M≤105,
    1≤K≤1000,
    1≤L≤100
    输入样例:
    2 2
    1 2 5
    2 1 4
    1 2 2
    输出样例:
    14
    

    分析:

    这题是求所有路径当中第k小的路径,也就意味着,我们要从全局(所有路径)当中,找到第k小的那条路径,所以,我们可能甚至需要将所有路径都给求出来呢。
    这时候,就与一般的堆优化版dijkstra算法有所不同了,我们将点x所有可达(也就是等扩展到)的点y都给加入到队列中。然后不断的扩展。
    在堆优化版的dijkstra算法中,我们是只将更新后的点y加入到队列中。
    
    注意,这里有个结论,【我还没搞懂对错,因为这题的预估函数确实选的挺巧妙,f=g】
    只能保证终点第k次被取出的时候,是第k小的,而其他点是不能保证的。 

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    
    using namespace std;
    
    typedef pair<int, int> PII;
    typedef pair<int, PII> PIII;
    
    #define x first
    #define y second
    
    const int N = 1010, M = 200010;
    
    int n, m;
    int head[N], rhead[N], ver[M], edge[M], Next[M], tot;
    int S, T, K;
    
    void add(int head[], int x, int y, int z)
    {
        ver[++ tot] = y, edge[tot] = z, Next[tot] = head[x], head[x] = tot;
    }
    
    int f[N];
    bool st[N];
    
    void dijkstra()
    {
        memset(f, 0x3f, sizeof f);
        f[T] = 0;
        priority_queue<PII, vector<PII>, greater<PII>> q;
        q.push({0, T});
        
        while (q.size())
        {
            PII t = q.top();
            q.pop();
            
            int x = t.y;
            
            if (st[x]) continue;//第一次被取出的点,一定是从起点到当前点的最短路
            st[x] = true;//既然已经求出这个点的最短路,也用这个x的最短路扩展过其他的y,那么说明不需要再用到它了
            for (int i = rhead[x]; i; i = Next[i])
            {
                int y = ver[i], z = edge[i];
                
                if (f[y] > f[x] + z)
                {
                    f[y] = f[x] + z;
                    q.push({f[y], y});
                }
            }
        }
    }
    
    int bfs()
    {
        priority_queue<PIII, vector<PIII>, greater<PIII>> q;
        q.push({f[S], {0, S}});
        
        int cnt[N] = {0};
        
        while (q.size())
        {
            PIII t = q.top();
            q.pop();
            
            int x = t.y.y, distance = t.y.x;
            
            cnt[x] ++;
            if (cnt[T] == K) return distance;
            for (int i = head[x]; i; i = Next[i])
            {
                int y = ver[i], z = edge[i];
                if (cnt[y] < K)
                q.push({distance + z + f[y], {distance + z, y}});
            }
        }
        return -1;
    }
    int main()
    {
        scanf("%d%d", &n, &m);
        while (m -- ) 
        {
            int x, y, z; scanf("%d%d%d", &x, &y, &z);
            add(head, x, y, z), add(rhead, y, x, z);
        }
        scanf("%d%d%d", &S, &T, &K);
        
        //从终点T向每个点求下最短路,f[x]
        dijkstra();
        //当S==T的时候,最短路为0,又因为题目中说最短要包含一条边,所以,给K++,算是跳一下0这条边
        if (S == T) K ++;
        //然后,我们正着做一遍A*算法,注意要将x所有可达的点全部
        //都加入优先队列中去,不需要判断距离的大小,不需要将扩展过的才放入队列中
        printf("%d
    ", bfs());
        
        return 0;
    }
    

      

  • 相关阅读:
    专利申请流程
    安装Fedora16与Windows7共存双系统
    rpm检查依赖性
    C++中的static函数和extern关键字
    asp.net 浏览服务器文件
    如何用批处理文件写:获取当前日期的前一天
    有一个无效 SelectedValue,因为它不在项目列表中。
    .net 4.0 检测到有潜在危险的 Request.Form 值。
    ckeditor 在C#中使用
    使用任务计划程序自动执行任务
  • 原文地址:https://www.cnblogs.com/Iamcookieandyou/p/14702071.html
Copyright © 2011-2022 走看看