- 题目: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;
}
#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;
}