河工大第一届校赛 K.星星拜年(多源最短路、链式前向星)

  • 题目:https://ac.nowcoder.com/acm/contest/15703/K
  • 思路:多源最短路 + 链式前向星存图
  • 解析:多源最短路核心:构造一个超级起始点(设为0)到所有起点的距离为0,再构造一个超级终点(设为n+1),所有终点到该超级终点距离为0,最后求超级起点到超级终点距离即可(转换成单源最短路),那么可用dijkstra或者spfa跑一遍多源最短路(此题将花费转换成路径长度即可);
    这题多一个限制条件:礼物数量,开一个cnt数组记录一下超级起点到第i个点在当前最短距离条件下所需最少的礼物数即可。
  • 代码(dijkstra):
#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
const int M = 2e5 + 5;
const int N = 1e5 + 5;
int n, m, n1, n2, k;
int idx = 0;
int head[N], dis[N], st[N];
int cnt[N]; //起点到第i个点的最短距离条件下所需最少的礼物数
struct Edge
{
    int next, to, w;
}edge[M];
void add(int u, int v, int w)
{
    edge[++idx].next = head[u];
    edge[idx].to = v;
    edge[idx].w = w;
    head[u] = idx;
}
void dijkstra()
{
    memset(dis, 0x3f, sizeof dis);
    priority_queue<PII, vector<PII>, greater<PII> >heap;
    heap.push({0, 0});
    dis[0] = 0;
    while(heap.size())
    {
        PII t = heap.top();
        heap.pop();
        int node = t.second, val = t.first;
        if(st[node]) continue;
        st[node] = 1;
        for(int i = head[node]; i != -1; i = edge[i].next)
        {
            int u = edge[i].to, w = edge[i].w;
            if(dis[u] == val + w)  //最短距离相等则比较消耗的礼物数量
                cnt[u] = min(cnt[u], cnt[node] + 1);
            else if(dis[u] > val + w)
            {
                dis[u] = val + w;
                cnt[u] = cnt[node] + 1;
                heap.push({dis[u], u});
            }
        }
    }
}
int main()
{
    memset(head, -1, sizeof head);
    cin >> n >> m >> n1 >> n2 >> k;
    for(int i = 1; i <= n1; i++)
    {
        int x;
        cin >> x;
        add(0, x, 0); //构造一个超级起始点到所有起点的距离为0
    }
    for(int i = 1; i <= n2; i++)
    {
        int x;
        cin >> x;
        add(x, n + 1, 0); //构造一个超级终点,所有终点到该点距离为0
    }
    for(int i = 1; i <= m; i++)
    {
        int u, v, w;
        cin >> u >> v >> w;
        add(u, v, w);
    }
    dijkstra();
    if(dis[n+1] == 0x3f3f3f3f || cnt[n+1] - 1 >= k) cout << "we break up" << endl;
    else cout << k - (cnt[n+1] - 1) << endl; //去除超级终点的礼物数消耗
    return 0;
}

  • 代码(spfa):
#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;
const int M = 2e5 + 5;
const int N = 1e5 + 5;
int n, m, n1, n2, k;
int idx = 0;
int head[N], dis[N], st[N];
int cnt[N]; //起点到第i个点的最短距离条件下所需最少的礼物数
struct Edge
{
    int next, to, w;
}edge[M];
void add(int u, int v, int w)
{
    edge[++idx].next = head[u];
    edge[idx].to = v;
    edge[idx].w = w;
    head[u] = idx;
}
void spfa()
{
    memset(dis, 0x3f, sizeof dis);
    queue<int> q;
    q.push(0);
    st[0] = 1, dis[0] = 0;
    while(q.size())
    {
        int node = q.front();
        q.pop();
        st[node] = 0;
        for(int i = head[node]; i != -1; i = edge[i].next)
        {
            int u = edge[i].to, w = edge[i].w;
            if(dis[u] == dis[node] + w) cnt[u] = min(cnt[u], cnt[node] + 1);
            else if(dis[u] > dis[node] + w)
            {
                dis[u] = dis[node] + w;
                cnt[u] = cnt[node] + 1;
                if(!st[node])
                {
                    q.push(u);
                    st[u] = 1;
                }
            }
        }
    }
}
int main()
{
    memset(head, -1, sizeof head);
    cin >> n >> m >> n1 >> n2 >> k;
    for(int i = 1; i <= n1; i++)
    {
        int x;
        cin >> x;
        add(0, x, 0); //构造一个超级起始点到所有起点的距离为0
    }
    for(int i = 1; i <= n2; i++)
    {
        int x;
        cin >> x;
        add(x, n + 1, 0); //构造一个超级终点,所有终点到该点距离为0
    }
    for(int i = 1; i <= m; i++)
    {
        int u, v, w;
        cin >> u >> v >> w;
        add(u, v, w);
    }
    spfa();
    if(dis[n+1] == 0x3f3f3f3f || cnt[n+1] - 1 >= k) cout << "we break up" << endl;
    else cout << k - (cnt[n+1] - 1) << endl;
    return 0;
}

posted @ 2021-06-03 23:33  ~K2MnO4  阅读(97)  评论(0)    收藏  举报