[USACO15JAN]Cow Routing S 题解
[USACO15JAN]Cow Routing S 题解
题意很简单,不用多说。
先来看如何建边:因为一条航线一次性可以经过多个城市,还可以反复上下飞机。所以我们枚举一条航线里的每两个城市进行连边,边权都相等。
因为题目还要求经过几条边,所以我们在建边的时候记录下这条边起点、终点、边权、途径的城市个数。然后跑一遍 Dijkstra 就行。
其他注意事项:
除了最短路用的记录花费的数组,还需要开一个记录保证花费最小的情况下经过最小边数的数组。
因为建边比较多,前向星数组要开很大。
Code
#include <iostream>
#include <cstring>
#include <bitset>
#include <queue>
using namespace std;
const int N = 1e3 + 5, M = 5e6 + 5;
struct node
{
long long dis;
int road, u;
bool operator > (const node &x) const {return dis == x.dis ? road > x.road : dis > x.dis;}
};
priority_queue<node, vector<node>, greater<node>> p;
int head[N], to[M], we[M], ne[M], c[M], idx = 1;
int s, t, n, a[N], road[N];
long long dist[N];
bitset<N> st;
void add(int u, int v, int w, int cnt)
{
c[idx] = cnt;
to[idx] = v;
we[idx] = w;
ne[idx] = head[u];
head[u] = idx ++ ;
}
void Dijkstra()
{
memset(dist, 0x3f, sizeof dist);
memset(road, 0x3f, sizeof road);
road[s] = dist[s] = 0;
p.push({0, 0, s});
while (!p.empty())
{
int u = p.top().u;
p.pop();
if (st[u]) continue;
st[u] = true;
for (int i = head[u]; i; i = ne[i])
{
int v = to[i], w = we[i], cnt = c[i];
if (dist[v] > dist[u] + w)
{
dist[v] = dist[u] + w;
road[v] = road[u] + cnt;
p.push({dist[v], road[v], v});
}
else if (dist[v] == dist[u] + w && road[v] > road[u] + cnt)
{
road[v] = road[u] + cnt;
p.push({dist[v], road[v], v});
}
}
}
}
int main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> s >> t >> n;
int w, cnt;
for (int i = 1; i <= n; i = i ++ )
{
cin >> w >> cnt;
for (int j = 1; j <= cnt; j = j ++ )
{
cin >> a[j];
for (int k = 1; k < j; k = k ++ ) add(a[k], a[j], w, j - k); // 经过几个城市
}
}
Dijkstra();
if (dist[t] == 0x3f3f3f3f3f3f3f3f) printf("-1 -1\n");
else printf("%lld %d\n", dist[t], road[t]);
return 0;
}