单源最短路的简单建图

920. 最优乘车 - AcWing题库

思路:只要两个点之间可达,距离就是1

每个车站到达后面的车站的距离都是1
那么1到达n的最短距离就是转车次数+1

由于距离都是1,可以用bfs求最短路

注意:

这里的车站是单程的 

技巧:

sstream读入

#include <cstring>
#include <iostream>
#include <algorithm>
#include <sstream>

using namespace std;

const int N = 510;

int m, n;
bool g[N][N];
int dist[N];
int stop[N];
int q[N];

void bfs()
{
    int hh = 0, tt = 0;
    memset(dist, 0x3f, sizeof dist);
    q[0] = 1;
    dist[1] = 0;

    while (hh <= tt)
    {
        int t = q[hh ++ ];

        for (int i = 1; i <= n; i ++ )
            if (g[t][i] && dist[i] > dist[t] + 1)
            {
                dist[i] = dist[t] + 1;
                q[ ++ tt] = i;
            }
    }
}

int main()
{
    cin >> m >> n;

    string line;
    getline(cin, line);
    while (m -- )
    {
        getline(cin, line);
        stringstream ssin(line);
        int cnt = 0, p;
        while (ssin >> p) stop[cnt ++ ] = p;
        for (int j = 0; j < cnt; j ++ )
            for (int k = j + 1; k < cnt; k ++ )
                g[stop[j]][stop[k]] = true;
    }

    bfs();

    if (dist[n] == 0x3f3f3f3f) puts("NO");
    else cout << dist[n] - 1 << endl;
    
    return 0;
}


903. 昂贵的聘礼 - AcWing题库

思路:超级源点 

直观的想,我们最容易想到的思路是从我们的目标物开始往下寻找替代品,对于寻找到的替代品,看看有没有该替代品的替代品。即cost[root] = new_money + cost[tmp],然后再递归求cost[tmp],以此往复。

但是这样的话就是一个DFS了,由于本题n=100,所以dfs是不可行的。

既然我们不能从头开始寻找一条最短路,那么我们能不能从尾开始求一条最短路呢,这样就不用递归了。

事实上我们不能从尾开始找到一条最短路,或者说我们不能直接从尾找到一条最短路,因为我们的尾有很多,但在求最短路的时候,只能有一个尾巴。

——————————————————正解———————————————————

所以说,我们建立一个超级源点0,从0建立一条边到每个物品,权值为物品的价值。代表花费多少钱就可以购买这个物品

若某个物品拥有替代品,代表从替代品建立一条边到这个物品,价值为替代的价值。 代表我有了这个替代品,那么还需要花费多少就能买这个物品

最后就是等级制度。我们可以枚举每个等级区间,每次求最短路是只能更新在这个区间里面的物品。枚举所有情况求一个最小值就可以了。 特别注意的是区间必须包含1点。 那么范围就是【L[1] - m, L[1]】

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 110;

int g[N][N], level[N];
int n, m;
int dist[N];
bool st[N];

int dijkstra(int l, int r)
{
    memset(dist, 0x3f, sizeof dist);
    memset(st, false, sizeof st);
    dist[0] = 0;//从虚拟源点出发
    
    for(int u = 1; u <= n; u ++ )
    {
        int t = -1;
        for(int i = 0; i <= n; i ++ )
            if(!st[i] && (t == -1 || dist[i] < dist[t]))    
                t = i;
        
        st[t] = true;
        //如果选取的点不符合区间范围
        if(t && level[t] < l || level[t] > r)    //当选取的点是虚拟源点时需要特判
            continue;
        
        for(int i = 1; i <= n; i ++ )   
            if(level[i] >= l && level[i] <= r)//被更新的点也要满足区间范围
                dist[i] = min(dist[i], dist[t] + g[t][i]);
    }

    return dist[1];
}

int main()
{
    memset(g, 0x3f, sizeof g);
    for(int i = 0; i <= n; i ++ )   g[i][i] = 0;
    
    cin >> m >> n;
    for(int i = 1; i <= n; i ++ )
    {
        int price, k, id, cost;
        cin >> price >> level[i] >> k;
        g[0][i] = min(g[0][i], price);
        while(k -- )
        {
            cin >> id >> cost;
            g[id][i] = min(g[id][i], cost);
        }
    }

    int res = 0x3f3f3f3f;
    for (int i = level[1] - m; i <= level[1]; i ++ ) res = min(res, dijkstra(i, i + m));
    cout << res << endl;
    
    return 0;
}

posted @ 2022-05-05 08:41  光風霽月  阅读(11)  评论(0编辑  收藏  举报